UNPKG

@roadiehq/backstage-plugin-jira

Version:
223 lines (220 loc) 10 kB
import React, { useState, useEffect } from 'react'; import { makeStyles, createStyles, Box, IconButton, Menu, MenuItem, Checkbox, Button, Grid, Typography, Divider, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, TablePagination, Avatar } from '@material-ui/core'; import Alert from '@material-ui/lab/Alert'; import { InfoCard, Progress } from '@backstage/core-components'; import { useEntity } from '@backstage/plugin-catalog-react'; import 'xml-js'; import 'luxon'; import 'uuid'; import { useAnalytics } from '@backstage/core-plugin-api'; import 'react-use'; import '../../api/index.esm.js'; import { useProjectInfo } from '../../hooks/useProjectInfo.esm.js'; import { useProjectEntity } from '../../hooks/useProjectEntity.esm.js'; import { Status } from './components/Status.esm.js'; import { ActivityStream } from '../EntityJiraActivityStreamCard/ActivityStream.esm.js'; import { Selectors } from './components/Selectors.esm.js'; import { useEmptyIssueTypeFilter } from '../../hooks/useEmptyIssueTypeFilter.esm.js'; import MoreVertIcon from '@material-ui/icons/MoreVert'; import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; const useStyles = makeStyles( (theme) => createStyles({ infoCard: { marginBottom: theme.spacing(3), "& + .MuiAlert-root": { marginTop: theme.spacing(3) } }, root: { flexGrow: 1, fontSize: "0.75rem", "& > * + *": { marginTop: theme.spacing(1) } }, ticketLink: { color: theme.palette.link, textDecoration: "none", transition: "color 0.3s", "&:hover": { color: theme.palette.linkHover } } }) ); const CardProjectDetails = ({ project, component }) => /* @__PURE__ */ React.createElement(Box, { display: "inline-flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(Avatar, { alt: "", src: project.iconUrl }), /* @__PURE__ */ React.createElement(Box, { ml: 1 }, project.name, " | ", project.type, component ? /* @__PURE__ */ React.createElement(Box, null, "component: ", component) : null)); const JiraOverviewCard = (props) => { const { hideIssueFilter } = props; const { entity } = useEntity(); const classes = useStyles(); const analytics = useAnalytics(); const { projectKey, component, tokenType, label } = useProjectEntity(entity); const [statusesNames, setStatusesNames] = useState([]); const { project, issues, tickets, ticketIds, projectLoading, projectError, fetchProjectInfo } = useProjectInfo(projectKey, component, label, statusesNames); const { issueTypes: displayIssues, type, changeType } = useEmptyIssueTypeFilter(issues); const [anchorEl, setAnchorEl] = React.useState(null); const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(5); useEffect(() => { setPage(0); }, [tickets]); const handleClick = (event) => { setAnchorEl(event.currentTarget); }; const handleClose = () => { setAnchorEl(null); }; return /* @__PURE__ */ React.createElement( InfoCard, { className: classes.infoCard, title: "Jira", subheader: project && /* @__PURE__ */ React.createElement( Box, { display: "flex", justifyContent: "space-between", width: "100%", alignItems: "center" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(CardProjectDetails, { project, component }), /* @__PURE__ */ React.createElement(Box, { display: "inline-flex", pl: 1 }, /* @__PURE__ */ React.createElement( IconButton, { "aria-label": "more", "aria-controls": "long-menu", "aria-haspopup": "true", onClick: handleClick }, /* @__PURE__ */ React.createElement(MoreVertIcon, null) ), /* @__PURE__ */ React.createElement( Menu, { id: "simple-menu", anchorEl, keepMounted: true, open: Boolean(anchorEl), onClose: handleClose }, /* @__PURE__ */ React.createElement(MenuItem, { onClick: changeType }, /* @__PURE__ */ React.createElement(Checkbox, { checked: type === "all" }), /* @__PURE__ */ React.createElement(React.Fragment, null, "Show empty issue types")) ))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement( Button, { variant: "outlined", color: "primary", size: "medium", endIcon: /* @__PURE__ */ React.createElement(ArrowForwardIcon, null), href: `${project?.url}/browse/${projectKey}`, target: "_blank" }, "Open in JIRA" )) ) }, projectLoading && !(project && issues) ? /* @__PURE__ */ React.createElement(Progress, null) : null, projectError ? /* @__PURE__ */ React.createElement(Alert, { severity: "error", className: classes.infoCard }, projectError.message) : null, project && issues ? /* @__PURE__ */ React.createElement("div", { className: classes.root }, !hideIssueFilter && /* @__PURE__ */ React.createElement( Selectors, { projectKey, statusesNames, setStatusesNames, fetchProjectInfo } ), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, displayIssues?.map((issueType) => /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true, key: issueType.name }, /* @__PURE__ */ React.createElement( Box, { width: 100, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React.createElement(Status, { name: issueType.name, iconUrl: issueType.iconUrl }), /* @__PURE__ */ React.createElement(Typography, { variant: "h4" }, issueType.total) )))), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(TableContainer, null, /* @__PURE__ */ React.createElement(Table, { className: classes.infoCard, "aria-label": "tickets-table" }, /* @__PURE__ */ React.createElement(TableHead, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, null, "Key"), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, "Summary"), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, "Priority"), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, "Status"), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, "Created"), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, "Updated"), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, "Assignee"))), /* @__PURE__ */ React.createElement(TableBody, null, tickets && tickets.length > 0 ? tickets.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((ticket) => /* @__PURE__ */ React.createElement(TableRow, { key: ticket?.key }, /* @__PURE__ */ React.createElement(TableCell, { component: "th" }, /* @__PURE__ */ React.createElement( "a", { href: `${project?.url}/browse/${ticket?.key}`, target: "_blank", rel: "noopener noreferrer", className: classes.ticketLink }, ticket?.key )), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, ticket?.summary), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, /* @__PURE__ */ React.createElement( "img", { src: ticket?.priority?.iconUrl, alt: ticket?.priority?.name, title: ticket?.priority?.name, width: "20px" } )), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, ticket?.status), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, new Date(ticket?.created).toLocaleDateString()), /* @__PURE__ */ React.createElement(TableCell, { align: "left" }, new Date(ticket?.updated).toLocaleDateString()), /* @__PURE__ */ React.createElement( TableCell, { align: "left", style: { display: "flex", alignItems: "center" } }, ticket?.assignee?.displayName ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement( "img", { src: ticket?.assignee?.avatarUrl, alt: ticket?.assignee?.displayName, title: ticket?.assignee?.displayName, style: { marginRight: "10px" }, width: "30px" } ), ticket?.assignee?.displayName) : /* @__PURE__ */ React.createElement("span", null, "Not Assigned") ))) : /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, { colSpan: 7, align: "center" }, "No Jira tickets available.")))), /* @__PURE__ */ React.createElement( TablePagination, { rowsPerPageOptions: [5, 10, 20], component: "div", count: tickets?.length ?? 0, rowsPerPage, page, onPageChange: (_event, newPage) => { setPage(newPage); analytics.captureEvent( "paginate", `page: ${newPage}, size: ${rowsPerPage}` ); }, onRowsPerPageChange: (event) => { setRowsPerPage(parseInt(event.target.value, 10)); setPage(0); analytics.captureEvent( "paginate", `page: 0, size: ${parseInt(event.target.value, 10)}` ); } } )), /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle1" }, "Activity Stream"), /* @__PURE__ */ React.createElement( ActivityStream, { projectKey, tokenType, componentName: component, label, ticketIds } ))) : null ); }; export { JiraOverviewCard }; //# sourceMappingURL=JiraOverviewCard.esm.js.map