feat: github issues plugin mvp

Signed-off-by: Kamil Wolny <mrwolny@gmail.com>
This commit is contained in:
Kamil Wolny
2022-07-28 14:35:54 +01:00
parent c7dd03bf96
commit c9c6bf3932
35 changed files with 1770 additions and 20 deletions
+1
View File
@@ -33,6 +33,7 @@
"@backstage/plugin-gcalendar": "^0.3.4-next.0",
"@backstage/plugin-gcp-projects": "^0.3.27-next.0",
"@backstage/plugin-github-actions": "^0.5.8-next.0",
"@backstage/plugin-github-issues": "^0.0.0",
"@backstage/plugin-gocd": "^0.1.14-next.0",
"@backstage/plugin-graphiql": "^0.2.40-next.0",
"@backstage/plugin-home": "^0.4.24-next.0",
+2
View File
@@ -100,6 +100,7 @@ import { techDocsPage } from './components/techdocs/TechDocsPage';
import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow';
import { PermissionedRoute } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
import { GitHubIssuesPage } from '@backstage/plugin-github-issues';
const app = createApp({
apis,
@@ -241,6 +242,7 @@ const routes = (
</Route>
<Route path="/azure-pull-requests" element={<AzurePullRequestsPage />} />
<Route path="/apache-airflow" element={<ApacheAirflowPage />} />
<Route path="/github-issues" element={<GitHubIssuesPage />} />
</FlatRoutes>
);
@@ -150,6 +150,11 @@ import {
ReportIssue,
} from '@backstage/plugin-techdocs-module-addons-contrib';
import {
GitHubIssuesCard,
GitHubIssuesPage,
} from '@backstage/plugin-github-issues';
const customEntityFilterKind = ['Component', 'API', 'System'];
const EntityLayoutWrapper = (props: { children?: ReactNode }) => {
@@ -325,6 +330,10 @@ const overviewContent = (
<EntityAboutCard variant="gridItem" />
</Grid>
<Grid item xs={12}>
<GitHubIssuesCard />
</Grid>
<Grid item md={6} xs={12}>
<EntityCatalogGraphCard variant="gridItem" height={400} />
</Grid>
@@ -624,6 +633,9 @@ const userPage = (
entityFilterKind={customEntityFilterKind}
/>
</Grid>
<Grid item xs={12}>
<GitHubIssuesCard />
</Grid>
</Grid>
</EntityLayout.Route>
</EntityLayoutWrapper>
@@ -646,8 +658,14 @@ const groupPage = (
<Grid item xs={12}>
<EntityMembersListCard />
</Grid>
<Grid item xs={12}>
<GitHubIssuesCard />
</Grid>
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="github-issues" title="GitHub Issues">
<GitHubIssuesPage />
</EntityLayout.Route>
</EntityLayoutWrapper>
);
+1
View File
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
+13
View File
@@ -0,0 +1,13 @@
# github-issues
Welcome to the github-issues plugin!
_This plugin was created through the Backstage CLI_
## Getting started
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/github-issues](http://localhost:3000/github-issues).
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { createDevApp } from '@backstage/dev-utils';
import { gitHubIssuesPlugin, GitHubIssuesPage } from '../src/plugin';
createDevApp()
.registerPlugin(gitHubIssuesPlugin)
.addPage({
element: <GitHubIssuesPage />,
title: 'Root Page',
path: '/github-issues',
})
.render();
+60
View File
@@ -0,0 +1,60 @@
{
"name": "@backstage/plugin-github-issues",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "frontend-plugin"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"prettier": "@spotify/prettier-config",
"dependencies": {
"@backstage/catalog-model": "^1.0.3",
"@backstage/core-components": "^0.9.5",
"@backstage/core-plugin-api": "^1.0.3",
"@backstage/integration": "^1.2.1",
"@backstage/plugin-catalog-react": "^1.1.1",
"@backstage/theme": "^0.2.15",
"@material-ui/core": "^4.12.4",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.61",
"@octokit/rest": "^18.12.0",
"luxon": "^2.4.0",
"react-use": "^17.2.4"
},
"peerDependencies": {
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.17.2",
"@backstage/core-app-api": "^1.0.3",
"@backstage/dev-utils": "^1.0.3",
"@backstage/test-utils": "^1.1.1",
"@spotify/prettier-config": "^13.0.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^12.1.3",
"@testing-library/user-event": "^14.0.0",
"@types/jest": "*",
"@types/node": "*",
"cross-fetch": "^3.1.5",
"msw": "^0.42.0",
"prettier": "^2.7.1"
},
"files": [
"dist"
]
}
@@ -0,0 +1,49 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { GitHubIssues } from './GitHubIssues';
import { ThemeProvider } from '@material-ui/core';
import { lightTheme } from '@backstage/theme';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import {
setupRequestMockHandlers,
renderInTestApp,
} from '@backstage/test-utils';
// test for repo duplicates
describe('GitHubIssues', () => {
const server = setupServer();
// Enable sane handlers for network requests
setupRequestMockHandlers(server);
// setup mock response
beforeEach(() => {
server.use(
rest.get('/*', (_, res, ctx) => res(ctx.status(200), ctx.json({}))),
);
});
it('should render', async () => {
const rendered = await renderInTestApp(
<ThemeProvider theme={lightTheme}>
<GitHubIssues mode="card" />
</ThemeProvider>,
);
expect(rendered.getByText('Welcome to github-issues!')).toBeInTheDocument();
});
});
@@ -0,0 +1,150 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Box, IconButton, Typography } from '@material-ui/core';
import { InfoCard, Progress } from '@backstage/core-components';
import RefreshIcon from '@material-ui/icons/Refresh';
import { useEntityGitHubRepositories } from '../../hooks/useEntityGitHubRepositories';
import {
RepoIssues,
useGetIssuesByRepoFromGitHub,
} from '../../hooks/useGetIssuesByRepoFromGitHub';
import { IssueList } from './IssuesList';
import { NoRepositoriesInfo } from './NoRepositoriesInfo';
export type PluginMode = 'page' | 'card';
export type Props = {
mode: PluginMode;
itemsPerPage?: number;
itemsPerRepo?: number;
};
export const GitHubIssues = ({
itemsPerPage = 10,
itemsPerRepo = 40,
}: Props) => {
const [isLoading, setIsLoading] = React.useState(true);
const [activeFilter, setActiveFilter] = React.useState<Array<string>>([]);
const [issuesByRepository, setIssuesByRepository] =
React.useState<Record<string, RepoIssues>>();
const { repositories } = useEntityGitHubRepositories();
const getIssues = useGetIssuesByRepoFromGitHub();
const filters = React.useMemo(
() =>
issuesByRepository
? Object.keys(issuesByRepository)
.filter(repo => issuesByRepository[repo].issues.totalCount > 0)
.map(repo => ({
label: `${repo} (${issuesByRepository[repo].issues.totalCount})`,
value: repo,
}))
: [],
[issuesByRepository],
);
const totalIssuesInGitHub = React.useMemo(
() =>
issuesByRepository
? Object.values(issuesByRepository).reduce(
(acc, { issues: { totalCount } }) => acc + totalCount,
0,
)
: 0,
[issuesByRepository],
);
const filteredRepos = React.useMemo(
() =>
issuesByRepository && activeFilter.length
? activeFilter.reduce(
(acc, val) => ({
[val]: issuesByRepository[val],
...acc,
}),
{},
)
: issuesByRepository,
[issuesByRepository, activeFilter],
);
const issues = React.useMemo(
() =>
filteredRepos
? Object.values(filteredRepos)
.map(({ issues: { edges } }) => edges)
.flat()
.sort((a, b) => {
if (a.node.updatedAt > b.node.updatedAt) {
return -1;
} else if (b.node.updatedAt > a.node.updatedAt) {
return 1;
}
return 0;
})
: [],
[filteredRepos],
);
const fetchGitHubIssues = React.useCallback(async () => {
setIsLoading(true);
const issuesByRepo = await getIssues(repositories, itemsPerRepo);
setIssuesByRepository(issuesByRepo);
setIsLoading(false);
}, [itemsPerRepo, getIssues, repositories]);
React.useEffect(() => {
if (repositories.length) {
fetchGitHubIssues();
} else {
setIsLoading(false);
}
}, [repositories.length, fetchGitHubIssues]);
if (!repositories.length) {
return <NoRepositoriesInfo />;
}
return (
<InfoCard
title={
<Box display="flex" justifyContent="flex-start" alignItems="center">
<Typography variant="h5">Open GitHub Issues</Typography>
<IconButton color="secondary" onClick={fetchGitHubIssues}>
<RefreshIcon />
</IconButton>
</Box>
}
>
{isLoading && <Progress />}
<IssueList
itemsPerPage={itemsPerPage}
issues={issues}
totalIssuesInGitHub={totalIssuesInGitHub}
setActiveFilter={setActiveFilter}
filters={filters}
/>
</InfoCard>
);
};
@@ -0,0 +1,61 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { FunctionComponent } from 'react';
import { Typography, Box, Avatar, makeStyles } from '@material-ui/core';
type Props = {
name?: string;
avatar?: string;
};
const useStyles = makeStyles(theme => ({
small: {
width: theme.spacing(4),
height: theme.spacing(4),
marginLeft: theme.spacing(1),
},
noAssignees: {
height: theme.spacing(4),
},
}));
export const Assignees: FunctionComponent<Props> = (props: Props) => {
const { name, avatar } = props;
const classes = useStyles();
// todo: many assignees -> NUM assignees + stock images on each other
return name ? (
<Box display="flex" alignItems="center" marginX={1}>
<Typography color="primary" variant="body2" component="p">
{name}
</Typography>
<Avatar alt={name} src={avatar} className={classes.small} />
</Box>
) : (
<Box display="flex" alignItems="center" marginX={1}>
<Typography
color="primary"
variant="body2"
component="p"
className={classes.noAssignees}
>
No assignees
</Typography>
</Box>
);
};
export default Assignees;
@@ -0,0 +1,40 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { FunctionComponent } from 'react';
import { ChatIcon } from '@backstage/core-components';
import { Box, Badge } from '@material-ui/core';
type Props = {
commentsCount: number;
};
export const CommentsCount: FunctionComponent<Props> = (props: Props) => {
const { commentsCount } = props;
return (
<Box
marginBottom={1}
style={{ marginRight: '12px' }}
display="flex"
justifyContent="flex-start"
alignSelf="flex-end"
>
<Badge badgeContent={commentsCount} color="primary">
<ChatIcon />
</Badge>
</Box>
);
};
@@ -0,0 +1,93 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { FunctionComponent } from 'react';
import { DateTime } from 'luxon';
import { Box, Paper, Typography, CardActionArea } from '@material-ui/core';
import Assignees from './Assignees';
import { CommentsCount } from './CommentsCount';
import Divider from '@material-ui/core/Divider';
type Props = {
title: string;
createdAt: string;
updatedAt?: string;
url: string;
authorName: string;
assigneeName?: string;
assigneeAvatar?: string;
authorAvatar?: string;
repositoryName: string;
commentsCount: number;
even: boolean;
};
const getElapsedTime = (isoDate: string) =>
DateTime.fromISO(isoDate).toRelative();
export const IssueCard: FunctionComponent<Props> = (props: Props) => {
const {
title,
createdAt,
updatedAt,
url,
assigneeName,
assigneeAvatar,
authorName,
repositoryName,
commentsCount,
} = props;
return (
<Box marginBottom={1}>
<Paper variant="outlined">
<CardActionArea href={url} target="_blank">
<Box padding={1}>
<Box display="flex" justifyContent="space-between">
<Typography color="primary" variant="body2" component="h2">
{repositoryName}
</Typography>
<Assignees name={assigneeName} avatar={assigneeAvatar} />
</Box>
<Box>
<Typography component="h2">
<b>{title}</b>
</Typography>
</Box>
<Divider variant="middle" />
<Box display="flex" justifyContent="space-between">
<Box marginY={1}>
<Typography variant="body2" component="p">
Created at: <strong>{getElapsedTime(createdAt)}</strong> by{' '}
<strong>{authorName}</strong>
</Typography>
{updatedAt && (
<Typography variant="body2" component="p">
Last update at: <strong>{getElapsedTime(updatedAt)}</strong>
</Typography>
)}
</Box>
{commentsCount > 0 && (
<CommentsCount commentsCount={commentsCount} />
)}
</Box>
</Box>
</CardActionArea>
</Paper>
</Box>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { IssueCard } from './IssueCard';
@@ -0,0 +1,64 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Select } from '@backstage/core-components';
import { SelectedItems } from '@backstage/core-components';
import { makeStyles, Box } from '@material-ui/core';
export type FilterItem = {
label: string;
value: string;
};
type Props = {
items: Array<FilterItem>;
totalIssuesInGitHub: number;
onChange: (active: Array<string>) => void;
};
const useStyles = makeStyles(theme => ({
filters: {
margin: theme.spacing(0, 0, 2, 0),
'& > div': {
width: '600px',
'& > div': {
maxWidth: '600px',
},
},
},
}));
const checkSelectedItems: (
onChange: (active: Array<string>) => void,
) => (active: SelectedItems) => void = onChange => active => {
return onChange(active as Array<string>);
};
export const Filters = ({ items, totalIssuesInGitHub, onChange }: Props) => {
const css = useStyles();
return (
<Box className={css.filters}>
<Select
placeholder={`All repositories (${totalIssuesInGitHub})`}
label=""
items={items}
multiple
onChange={checkSelectedItems(onChange)}
/>
</Box>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './Filters';
@@ -0,0 +1,101 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Box } from '@material-ui/core';
import { Pagination } from '@material-ui/lab';
import { IssueCard } from '../IssueCard';
import { Issue } from '../../../hooks/useGetIssuesByRepoFromGitHub';
import { Filters, FilterItem } from './Filters';
export type PluginMode = 'page' | 'card';
export type Props = {
itemsPerPage?: number;
issues: Array<{
node: Issue;
}>;
filters: Array<FilterItem>;
totalIssuesInGitHub: number;
setActiveFilter: (active: Array<string>) => void;
};
export const IssueList = ({
itemsPerPage = 10,
issues,
filters,
setActiveFilter,
totalIssuesInGitHub,
}: Props) => {
const [currentPage, setCurrentPage] = React.useState(1);
const displayIssues = issues.slice(
(currentPage - 1) * itemsPerPage,
(currentPage - 1) * itemsPerPage + itemsPerPage,
);
return (
<Box>
<Filters
items={filters}
onChange={setActiveFilter}
totalIssuesInGitHub={totalIssuesInGitHub}
/>
{displayIssues.length > 0 ? (
displayIssues.map(
(
{
node: {
title,
comments,
author,
createdAt,
updatedAt,
repository,
assignees,
url,
},
},
index,
) => (
<IssueCard
even={Boolean(index % 2)}
title={title}
createdAt={createdAt}
assigneeAvatar={assignees.edges[0]?.node.avatarUrl}
assigneeName={assignees.edges[0]?.node.login}
authorName={author.login}
updatedAt={updatedAt}
repositoryName={repository.nameWithOwner}
url={url}
commentsCount={comments.totalCount}
/>
),
)
) : (
<h1>No issues 🚀</h1>
)}
{issues.length / itemsPerPage > 1 ? (
<Pagination
count={Math.ceil(issues.length / itemsPerPage)}
onChange={(_, page) => setCurrentPage(page)}
/>
) : null}
</Box>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './IssuesList';
@@ -0,0 +1,27 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { EmptyState } from '@backstage/core-components';
export const NoRepositoriesInfo = () => {
return (
<EmptyState
title="There are no GitHub repositories connected to this entity."
missing="data"
/>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './NoRepositoriesInfo';
@@ -0,0 +1,16 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './GitHubIssues';
@@ -0,0 +1,24 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { FunctionComponent } from 'react';
import { GitHubIssues, Props as GitHubIssuesProps } from '../GitHubIssues';
type Props = Omit<GitHubIssuesProps, 'mode'>;
export const GitHubIssuesCard: FunctionComponent<Props> = props => {
return <GitHubIssues mode="card" {...props} />;
};
@@ -0,0 +1,16 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './GitHubIssuesCard';
@@ -0,0 +1,23 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { FunctionComponent } from 'react';
import { GitHubIssues, Props as GitHubIssuesProps } from '../GitHubIssues';
type Props = Omit<GitHubIssuesProps, 'mode'>;
export const GitHubIssuesPage: FunctionComponent<Props> = props => {
return <GitHubIssues mode="page" {...props} />;
};
@@ -0,0 +1,16 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './GitHubIssuesPage';
@@ -0,0 +1,69 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
import { useApi } from '@backstage/core-plugin-api';
import {
catalogApiRef,
humanizeEntityRef,
useEntity,
} from '@backstage/plugin-catalog-react';
import { useCallback, useEffect, useState } from 'react';
const GITHUB_PROJECT_SLUG_ANNOTATION = 'github.com/project-slug';
export const getProjectNameFromEntity = (entity: Entity): string => {
return entity?.metadata.annotations?.[GITHUB_PROJECT_SLUG_ANNOTATION] ?? '';
};
export function useEntityGitHubRepositories() {
const { entity } = useEntity();
const catalogApi = useApi(catalogApiRef);
const [repositories, setRepositories] = useState<string[]>([]);
const getRepositoriesNames = useCallback(async () => {
if (entity.kind === 'Component' || entity.kind === 'API') {
const entityName = getProjectNameFromEntity(entity);
if (entityName) {
setRepositories([entityName]);
}
return;
}
const entitiesList = await catalogApi.getEntities({
filter: {
kind: ['Component', 'API'],
'spec.owner': humanizeEntityRef(entity, { defaultKind: 'group' }),
},
});
const entitiesNames: string[] = entitiesList.items.map(componentEntity =>
getProjectNameFromEntity(componentEntity),
);
setRepositories([...new Set(entitiesNames)].filter(name => name.length));
}, [catalogApi, entity]);
useEffect(() => {
getRepositoriesNames();
}, [getRepositoriesNames]);
return {
repositories,
};
}
@@ -0,0 +1,105 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const mockGraphQLQuery = jest.fn(() => 'ti ri ri ri ra!');
jest.mock('./useOctokitGraphQL', () => ({
useOctokitGraphQL: jest.fn(() => mockGraphQLQuery),
}));
import React from 'react';
import { render } from '@testing-library/react';
import { useGetIssuesByRepoFromGitHub } from './useGetIssuesByRepoFromGitHub';
// fragment issues on Repository {
// issues(
// states: OPEN
// first: 40
// orderBy: { field: UPDATED_AT, direction: DESC }
// ) {
// totalCount
// edges {
// cursor
// node {
// assignees(first: 10) {
// edges {
// node {
// avatarUrl
// login
// }
// }
// }
// author {
// login
// avatarUrl
// url
// }
// repository {
// nameWithOwner
// }
// body
// title
// url
// participants {
// totalCount
// }
// updatedAt
// createdAt
// comments(last: 1) {
// totalCount
// }
// }
// }
// }
// }
// query {
// rateLimit {
// cost
// remaining
// }
// yomovie: repository(name: "yo-movie", owner: "mrwolny") {
// ...issues
// }
// ,
// yoanchor: repository(name: "yo-anchor", owner: "mrwolny") {
// ...issues
// }
// ,
// yomoviex: repository(name: "yo-movie", owner: "mrwolny") {
// ...issues
// }
// ,
// yoanchorx: repository(name: "yo-anchor", owner: "mrwolny") {
// ...issues
// }
// }
describe('useGetIssuesBeRepoFromGitHub', () => {
it('should rock!', async () => {
const Helper = () => {
const getIssues = useGetIssuesByRepoFromGitHub();
getIssues(['mrwolny/yo-yo', 'mrwolny/yoyo'], 10);
return <></>;
};
render(<Helper />);
expect(mockGraphQLQuery).toHaveBeenCalled();
});
});
@@ -0,0 +1,177 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { useOctokitGraphQL } from './useOctokitGraphQL';
type Assignee = {
avatarUrl: string;
login: string;
};
export type EdgesWithNodes<T> = {
edges: Array<{
node: T;
}>;
};
export type Node<T> = {
node: T;
};
type IssueAuthor = {
login: string;
};
export type Issue = {
cursor: string;
assignees: EdgesWithNodes<Assignee>;
author: IssueAuthor;
repository: {
nameWithOwner: string;
};
body: string;
title: string;
url: string;
participants: {
totalCount: number;
};
createdAt: string;
updatedAt: string;
comments: {
totalCount: number;
};
};
export type RepoIssues = {
issues: {
totalCount: number;
} & EdgesWithNodes<Issue>;
};
export type RepoIssuesQueryResults = Record<string, RepoIssues>;
const createQuery = (
repositories: Array<{
safeName: string;
name: string;
owner: string;
}>,
itemsPerRepo: number,
): string => {
const fragment = `
fragment issues on Repository {
issues(
states: OPEN
first: ${itemsPerRepo}
orderBy: { field: UPDATED_AT, direction: DESC }
) {
totalCount
edges {
cursor
node {
assignees(first: 10) {
edges {
node {
avatarUrl
login
}
}
}
author {
login
avatarUrl
url
}
repository {
nameWithOwner
}
body
title
url
participants {
totalCount
}
updatedAt
createdAt
comments(last: 1) {
totalCount
}
}
}
}
}
`;
const query = `
${fragment}
query {
${repositories.map(
({ safeName, name, owner }) => `
${safeName}: repository(name: "${name}", owner: "${owner}") {
...issues
}
`,
)}
}
`;
return query;
};
export const useGetIssuesByRepoFromGitHub = () => {
const graphql = useOctokitGraphQL<RepoIssuesQueryResults>();
const fn = React.useRef(
async (
repos: Array<string>,
itemsPerRepo: number,
): Promise<Record<string, RepoIssues>> => {
const safeNames: Array<string> = [];
const repositories = repos.map(repo => {
const [owner, name] = repo.split('/');
const safeNameRegex = /-|\./gi;
let safeName = name.replace(safeNameRegex, '');
while (safeNames.includes(safeName)) {
safeName += 'x';
}
safeNames.push(safeName);
return {
safeName,
name,
owner,
};
});
const issuesByRepo: RepoIssuesQueryResults = await graphql(
createQuery(repositories, itemsPerRepo),
);
return repositories.reduce((acc, { safeName, name, owner }) => {
acc[`${owner}/${name}`] = issuesByRepo[safeName];
return acc;
}, {} as Record<string, RepoIssues>);
},
);
return fn.current;
};
@@ -0,0 +1,21 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Issue } from './useGetIssuesByRepoFromGitHub';
export type GitHubIssues = {
getIssues: (repo?: string) => Array<Issue>;
getIssuesTotalCountByRepo: () => Record<string, { totalCount: number }>;
};
@@ -0,0 +1,47 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Octokit } from '@octokit/rest';
import {
useApi,
githubAuthApiRef,
configApiRef,
} from '@backstage/core-plugin-api';
import { readGitHubIntegrationConfigs } from '@backstage/integration';
let octokit: Octokit;
export const useOctokitGraphQL = <T>() => {
const auth = useApi(githubAuthApiRef);
const config = useApi(configApiRef);
const baseUrl = readGitHubIntegrationConfigs(
config.getOptionalConfigArray('integrations.github') ?? [],
)[0].apiBaseUrl;
return (path: string, options?: any): Promise<T> =>
auth
.getAccessToken(['repo'])
.then((token: string) => {
if (!octokit) {
octokit = new Octokit({ auth: token, ...(baseUrl && { baseUrl }) });
}
return octokit;
})
.then(octokitInstance => {
return octokitInstance.graphql(path, options);
});
};
+20
View File
@@ -0,0 +1,20 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export {
gitHubIssuesPlugin,
GitHubIssuesPage,
GitHubIssuesCard,
} from './plugin';
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { gitHubIssuesPlugin } from './plugin';
describe('github-issues', () => {
it('should export plugin', () => {
expect(gitHubIssuesPlugin).toBeDefined();
});
});
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
createPlugin,
createComponentExtension,
createRoutableExtension,
} from '@backstage/core-plugin-api';
import { rootRouteRef } from './routes';
export const gitHubIssuesPlugin = createPlugin({
id: 'github-issues',
routes: {
root: rootRouteRef,
},
});
export const GitHubIssuesCard = gitHubIssuesPlugin.provide(
createComponentExtension({
name: 'GitHubIssuesCard',
component: {
lazy: () =>
import('./components/GitHubIssuesCard').then(m => m.GitHubIssuesCard),
},
}),
);
export const GitHubIssuesPage = gitHubIssuesPlugin.provide(
createRoutableExtension({
name: 'GitHubIssuesPage',
component: () =>
import('./components/GitHubIssuesPage').then(m => m.GitHubIssuesPage),
mountPoint: rootRouteRef,
}),
);
+20
View File
@@ -0,0 +1,20 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createRouteRef } from '@backstage/core-plugin-api';
export const rootRouteRef = createRouteRef({
id: 'github-issues',
});
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '@testing-library/jest-dom';
import 'cross-fetch/polyfill';
+358 -20
View File
@@ -470,7 +470,7 @@
json5 "^2.1.2"
semver "^6.3.0"
"@babel/core@^7.18.5":
"@babel/core@^7.15.5", "@babel/core@^7.18.5":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59"
integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==
@@ -1594,7 +1594,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-react-constant-elements@^7.17.12":
"@babel/plugin-transform-react-constant-elements@^7.14.5", "@babel/plugin-transform-react-constant-elements@^7.17.12":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.18.9.tgz#ff6aeedd38f57ba6b41dcf824fcc8bcedb3e783f"
integrity sha512-IrTYh1I3YCEL1trjknnlLKTp5JggjzhKl/d3ibzPc97JhpFcDTr38Jdek/oX4cFbS6By0bXJcOkpRvJ5ZHK2wQ==
@@ -1758,7 +1758,7 @@
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/preset-env@^7.18.2":
"@babel/preset-env@^7.15.6", "@babel/preset-env@^7.18.2":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.9.tgz#9b3425140d724fbe590322017466580844c7eaff"
integrity sha512-75pt/q95cMIHWssYtyfjVlvI+QEZQThQbKvR9xH+F/Agtw/s4Wfc2V9Bwd/P39VtixB7oWxGdH4GteTTwYJWMg==
@@ -1859,7 +1859,7 @@
"@babel/types" "^7.4.4"
esutils "^2.0.2"
"@babel/preset-react@^7.17.12":
"@babel/preset-react@^7.14.5", "@babel/preset-react@^7.17.12":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d"
integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==
@@ -1880,7 +1880,7 @@
"@babel/helper-validator-option" "^7.16.7"
"@babel/plugin-transform-typescript" "^7.16.7"
"@babel/preset-typescript@^7.17.12":
"@babel/preset-typescript@^7.15.0", "@babel/preset-typescript@^7.16.0", "@babel/preset-typescript@^7.17.12":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz#ce64be3e63eddc44240c6358daefac17b3186399"
integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==
@@ -2019,6 +2019,135 @@
"@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
"@backstage/app-defaults@^1.0.4":
version "1.0.4"
resolved "https://registry.npmjs.org/@backstage/app-defaults/-/app-defaults-1.0.4.tgz#4e1ab2395900ffbd4d2b48c634c3e53409e4883b"
integrity sha512-Jhn34H1Ab5DHsSmeNkORnPpysGHPfk7ejcMKAAhgefbHND6ZcaCUiyy3SaccNJLqDEbWxGDYSXHDS6yQw0hgXg==
dependencies:
"@backstage/core-app-api" "^1.0.4"
"@backstage/core-components" "^0.10.0"
"@backstage/core-plugin-api" "^1.0.4"
"@backstage/plugin-permission-react" "^0.4.3"
"@backstage/theme" "^0.2.16"
"@material-ui/core" "^4.12.2"
"@material-ui/icons" "^4.9.1"
react-router-dom "6.0.0-beta.0"
"@backstage/cli@^0.17.2":
version "0.17.2"
resolved "https://registry.npmjs.org/@backstage/cli/-/cli-0.17.2.tgz#2387b8d24d8af4828b84baaa62e6b444ec4330e6"
integrity sha512-stRJWmokD7SXnclZ1dsVfA1stUP4PQPkbi3GkwY1zM84y4M20dU+YHde7MrTILMPnhMY+16WdTdfbeqLfXOJrw==
dependencies:
"@backstage/cli-common" "^0.1.9"
"@backstage/config" "^1.0.1"
"@backstage/config-loader" "^1.1.2"
"@backstage/errors" "^1.0.0"
"@backstage/release-manifests" "^0.0.4"
"@backstage/types" "^1.0.0"
"@hot-loader/react-dom-v16" "npm:@hot-loader/react-dom@^16.0.2"
"@hot-loader/react-dom-v17" "npm:@hot-loader/react-dom@^17.0.2"
"@manypkg/get-packages" "^1.1.3"
"@octokit/request" "^5.4.12"
"@rollup/plugin-commonjs" "^22.0.0"
"@rollup/plugin-json" "^4.1.0"
"@rollup/plugin-node-resolve" "^13.0.0"
"@rollup/plugin-yaml" "^3.1.0"
"@spotify/eslint-config-base" "^13.0.0"
"@spotify/eslint-config-react" "^13.0.0"
"@spotify/eslint-config-typescript" "^13.0.0"
"@sucrase/jest-plugin" "^2.1.1"
"@sucrase/webpack-loader" "^2.0.0"
"@svgr/plugin-jsx" "6.2.x"
"@svgr/plugin-svgo" "6.2.x"
"@svgr/rollup" "6.2.x"
"@svgr/webpack" "6.2.x"
"@types/webpack-env" "^1.15.2"
"@typescript-eslint/eslint-plugin" "^5.9.0"
"@typescript-eslint/parser" "^5.9.0"
"@yarnpkg/lockfile" "^1.1.0"
"@yarnpkg/parsers" "^3.0.0-rc.4"
bfj "^7.0.2"
buffer "^6.0.3"
chalk "^4.0.0"
chokidar "^3.3.1"
commander "^9.1.0"
css-loader "^6.5.1"
diff "^5.0.0"
esbuild "^0.14.10"
esbuild-loader "^2.18.0"
eslint "^8.6.0"
eslint-config-prettier "^8.3.0"
eslint-formatter-friendly "^7.0.0"
eslint-plugin-deprecation "^1.3.2"
eslint-plugin-import "^2.25.4"
eslint-plugin-jest "^26.1.2"
eslint-plugin-jsx-a11y "^6.5.1"
eslint-plugin-monorepo "^0.3.2"
eslint-plugin-react "^7.28.0"
eslint-plugin-react-hooks "^4.3.0"
eslint-webpack-plugin "^3.1.1"
express "^4.17.1"
fork-ts-checker-webpack-plugin "^7.0.0-alpha.8"
fs-extra "10.1.0"
glob "^7.1.7"
global-agent "^3.0.0"
handlebars "^4.7.3"
html-webpack-plugin "^5.3.1"
inquirer "^8.2.0"
jest "^27.5.1"
jest-css-modules "^2.1.0"
jest-runtime "^27.5.1"
jest-transform-yaml "^1.0.0"
json-schema "^0.4.0"
lodash "^4.17.21"
mini-css-extract-plugin "^2.4.2"
minimatch "5.1.0"
node-fetch "^2.6.7"
node-libs-browser "^2.2.1"
npm-packlist "^5.0.0"
ora "^5.3.0"
postcss "^8.1.0"
process "^0.11.10"
react-dev-utils "^12.0.0-next.60"
react-hot-loader "^4.13.0"
recursive-readdir "^2.2.2"
replace-in-file "^6.0.0"
rollup "^2.60.2"
rollup-plugin-dts "^4.0.1"
rollup-plugin-esbuild "^4.7.2"
rollup-plugin-postcss "^4.0.0"
rollup-pluginutils "^2.8.2"
run-script-webpack-plugin "^0.0.14"
semver "^7.3.2"
style-loader "^3.3.1"
sucrase "^3.20.2"
tar "^6.1.2"
terser-webpack-plugin "^5.1.3"
util "^0.12.3"
webpack "^5.66.0"
webpack-dev-server "^4.7.3"
webpack-node-externals "^3.0.0"
yaml "^1.10.0"
yml-loader "^2.1.0"
yn "^4.0.0"
zod "^3.11.6"
"@backstage/core-app-api@^1.0.3", "@backstage/core-app-api@^1.0.4":
version "1.0.4"
resolved "https://registry.npmjs.org/@backstage/core-app-api/-/core-app-api-1.0.4.tgz#3d667292de33e5de2c3e7ba256d4ae3bf85e46ad"
integrity sha512-mUF5EL74nes3fdQbfUMce/7wkgtQe6XRyDYhyP2eFdsaYFFhcexqBgJNBv6DZLRCjqc1iw5t0ZXCvMeO30l4Xw==
dependencies:
"@backstage/config" "^1.0.1"
"@backstage/core-plugin-api" "^1.0.4"
"@backstage/types" "^1.0.0"
"@backstage/version-bridge" "^1.0.1"
"@types/prop-types" "^15.7.3"
prop-types "^15.7.2"
react-router-dom "6.0.0-beta.0"
react-use "^17.2.4"
zen-observable "^0.8.15"
zod "^3.11.6"
"@backstage/core-components@^0.10.0":
version "0.10.0"
resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.10.0.tgz#d7f802eee82c49677f5d9b63d8c33b7405096caa"
@@ -2064,7 +2193,7 @@
zen-observable "^0.8.15"
zod "^3.11.6"
"@backstage/core-components@^0.9.0":
"@backstage/core-components@^0.9.0", "@backstage/core-components@^0.9.5":
version "0.9.5"
resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.5.tgz#5a0b34867aaee0549bfa67b39a69c09588fa3c7a"
integrity sha512-kfAdN70idiEqHeH9ZQryn6C0RxJEKiRc/7srYIz0CVV88zJfc0nmZ5C/S10Gkht2xWfm95tTSw2P1vEYIBbfxg==
@@ -2122,7 +2251,32 @@
react-router-dom "6.0.0-beta.0"
zen-observable "^0.8.15"
"@backstage/integration-react@^1.0.0":
"@backstage/dev-utils@^1.0.3":
version "1.0.4"
resolved "https://registry.npmjs.org/@backstage/dev-utils/-/dev-utils-1.0.4.tgz#401d092b9e6529cce2b56085a2b771db40ac8175"
integrity sha512-FT2I9eXS2zAsWPMkioa7PjnfzcY+mLv/PlXwOv94B2iSKXn2mz3iRDlek2uYBawiK0u4R5EmqGi8m1mEP/Zhxg==
dependencies:
"@backstage/app-defaults" "^1.0.4"
"@backstage/catalog-model" "^1.1.0"
"@backstage/core-app-api" "^1.0.4"
"@backstage/core-components" "^0.10.0"
"@backstage/core-plugin-api" "^1.0.4"
"@backstage/integration-react" "^1.1.2"
"@backstage/plugin-catalog-react" "^1.1.2"
"@backstage/test-utils" "^1.1.2"
"@backstage/theme" "^0.2.16"
"@material-ui/core" "^4.12.2"
"@material-ui/icons" "^4.9.1"
"@testing-library/jest-dom" "^5.10.1"
"@testing-library/react" "^12.1.3"
"@testing-library/user-event" "^14.0.0"
react-hot-loader "^4.13.0"
react-router "6.0.0-beta.0"
react-router-dom "6.0.0-beta.0"
react-use "^17.2.4"
zen-observable "^0.8.15"
"@backstage/integration-react@^1.0.0", "@backstage/integration-react@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@backstage/integration-react/-/integration-react-1.1.2.tgz#001a736f5ce222bf770a26c2c15b42705012e495"
integrity sha512-5MA9cuIDRviQ2Qi9slbHE2i2tBnIcs4JdRukc3sTw7zarcmYaVkDI7N2pQiBkVxATKwXoY8gDuEQD8VYr62cnw==
@@ -2137,7 +2291,7 @@
"@material-ui/lab" "4.0.0-alpha.57"
react-use "^17.2.4"
"@backstage/integration@^1.2.2":
"@backstage/integration@^1.2.1", "@backstage/integration@^1.2.2":
version "1.2.2"
resolved "https://registry.npmjs.org/@backstage/integration/-/integration-1.2.2.tgz#f0a9cb6ae31444832505d9f57dfa3f921fb0c6c0"
integrity sha512-MIttnW6xEIun94muo0nmJ3hK9ks9IgUvBsYGNwfxsKpWBv3g3zZ4cU0pXpUdtvzhWOHw7w3HQrSPEVmm6MSqbA==
@@ -2151,7 +2305,7 @@
lodash "^4.17.21"
luxon "^3.0.0"
"@backstage/plugin-catalog-react@^1.0.0", "@backstage/plugin-catalog-react@^1.1.2":
"@backstage/plugin-catalog-react@^1.0.0", "@backstage/plugin-catalog-react@^1.1.1", "@backstage/plugin-catalog-react@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-1.1.2.tgz#253a99d9ced5d751f9d1fb3d278511d754aaed4e"
integrity sha512-4O9TotC4aWuLA8gFcgvq/HeKXA80LUZ98WTdIqSA6iFjzh1BZbD/nvaG7Hw7X8m5C/Z7Ck4PM+ocB4XxxlVAZw==
@@ -2231,6 +2385,35 @@
qs "^6.9.4"
react-use "^17.2.4"
"@backstage/release-manifests@^0.0.4":
version "0.0.4"
resolved "https://registry.npmjs.org/@backstage/release-manifests/-/release-manifests-0.0.4.tgz#09aa80e8bd0731a23ed43acf78c6b9810c6cb56b"
integrity sha512-lwi6KRvzwsZLsuQ7i8HbLsta6pMCiegui8rWLs8T5735vzr1ls7h7efJp36guQBcQPHnAGHTgJ4Q/t1mk+d1VA==
dependencies:
cross-fetch "^3.1.5"
"@backstage/test-utils@^1.1.1", "@backstage/test-utils@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@backstage/test-utils/-/test-utils-1.1.2.tgz#60fda2d218511341f384fcdc9bf454db2fa8e762"
integrity sha512-nPQAKa5rcR/WDVDOSMVy1tHjKpr+P1VQt+SxkjxIy/AoKw0Acp2ioGetcbX9UWai/UxKrmQ/i5/GX8sfBFSPzw==
dependencies:
"@backstage/config" "^1.0.1"
"@backstage/core-app-api" "^1.0.4"
"@backstage/core-plugin-api" "^1.0.4"
"@backstage/plugin-permission-common" "^0.6.3"
"@backstage/plugin-permission-react" "^0.4.3"
"@backstage/theme" "^0.2.16"
"@backstage/types" "^1.0.0"
"@material-ui/core" "^4.12.2"
"@material-ui/icons" "^4.11.2"
"@testing-library/jest-dom" "^5.10.1"
"@testing-library/react" "^12.1.3"
"@testing-library/user-event" "^14.0.0"
cross-fetch "^3.1.5"
react-router "6.0.0-beta.0"
react-router-dom "6.0.0-beta.0"
zen-observable "^0.8.15"
"@balena/dockerignore@^1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d"
@@ -4757,7 +4940,7 @@
react-beautiful-dnd "^13.0.0"
react-double-scrollbar "0.0.15"
"@material-ui/core@^4.11.0", "@material-ui/core@^4.11.3", "@material-ui/core@^4.12.1", "@material-ui/core@^4.12.2", "@material-ui/core@^4.9.10", "@material-ui/core@^4.9.13":
"@material-ui/core@^4.11.0", "@material-ui/core@^4.11.3", "@material-ui/core@^4.12.1", "@material-ui/core@^4.12.2", "@material-ui/core@^4.12.4", "@material-ui/core@^4.9.10", "@material-ui/core@^4.9.13":
version "4.12.4"
resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz#4ac17488e8fcaf55eb6a7f5efb2a131e10138a73"
integrity sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==
@@ -4804,7 +4987,7 @@
prop-types "^15.7.2"
react-is "^16.8.0 || ^17.0.0"
"@material-ui/lab@^4.0.0-alpha.57", "@material-ui/lab@^4.0.0-alpha.60":
"@material-ui/lab@^4.0.0-alpha.57", "@material-ui/lab@^4.0.0-alpha.60", "@material-ui/lab@^4.0.0-alpha.61":
version "4.0.0-alpha.61"
resolved "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz#9bf8eb389c0c26c15e40933cc114d4ad85e3d978"
integrity sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg==
@@ -5431,6 +5614,19 @@
before-after-hook "^2.1.0"
universal-user-agent "^6.0.0"
"@octokit/core@^3.5.1":
version "3.6.0"
resolved "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085"
integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==
dependencies:
"@octokit/auth-token" "^2.4.4"
"@octokit/graphql" "^4.5.8"
"@octokit/request" "^5.6.3"
"@octokit/request-error" "^2.0.5"
"@octokit/types" "^6.0.3"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"
"@octokit/core@^4.0.0":
version "4.0.2"
resolved "https://registry.npmjs.org/@octokit/core/-/core-4.0.2.tgz#4eaf9c5fd39913b541c5e31a2b8fdc3cf50480bc"
@@ -5547,6 +5743,11 @@
resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6"
integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==
"@octokit/openapi-types@^12.11.0":
version "12.11.0"
resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0"
integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==
"@octokit/openapi-types@^12.4.0":
version "12.4.0"
resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.4.0.tgz#fd8bf5db72bd566c5ba2cb76754512a9ebe66e71"
@@ -5567,6 +5768,13 @@
resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437"
integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==
"@octokit/plugin-paginate-rest@^2.16.8":
version "2.21.3"
resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e"
integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==
dependencies:
"@octokit/types" "^6.40.0"
"@octokit/plugin-paginate-rest@^2.6.2":
version "2.7.0"
resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.7.0.tgz#6bb7b043c246e0654119a6ec4e72a172c9e2c7f3"
@@ -5599,6 +5807,14 @@
"@octokit/types" "^6.16.2"
deprecation "^2.3.1"
"@octokit/plugin-rest-endpoint-methods@^5.12.0":
version "5.16.2"
resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342"
integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==
dependencies:
"@octokit/types" "^6.39.0"
deprecation "^2.3.1"
"@octokit/plugin-rest-endpoint-methods@^6.0.0":
version "6.0.0"
resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.0.0.tgz#e4a55d83ec5a00e6b4d7a780f4ec9009095bff6f"
@@ -5675,6 +5891,16 @@
"@octokit/plugin-request-log" "^1.0.2"
"@octokit/plugin-rest-endpoint-methods" "5.3.1"
"@octokit/rest@^18.12.0":
version "18.12.0"
resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881"
integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==
dependencies:
"@octokit/core" "^3.5.1"
"@octokit/plugin-paginate-rest" "^2.16.8"
"@octokit/plugin-request-log" "^1.0.4"
"@octokit/plugin-rest-endpoint-methods" "^5.12.0"
"@octokit/rest@^19.0.3":
version "19.0.3"
resolved "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.3.tgz#b9a4e8dc8d53e030d611c053153ee6045f080f02"
@@ -5720,6 +5946,13 @@
dependencies:
"@octokit/openapi-types" "^12.7.0"
"@octokit/types@^6.40.0":
version "6.41.0"
resolved "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04"
integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==
dependencies:
"@octokit/openapi-types" "^12.11.0"
"@octokit/webhooks-methods@^3.0.0":
version "3.0.0"
resolved "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-3.0.0.tgz#4f4443605233f46abc5f85a857ba105095aa1181"
@@ -5989,7 +6222,7 @@
dependencies:
"@rollup/pluginutils" "^3.0.8"
"@rollup/plugin-node-resolve@^13.0.6":
"@rollup/plugin-node-resolve@^13.0.0", "@rollup/plugin-node-resolve@^13.0.6":
version "13.3.0"
resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c"
integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==
@@ -6134,21 +6367,41 @@
resolved "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
"@spotify/eslint-config-base@^13.0.0":
version "13.0.1"
resolved "https://registry.npmjs.org/@spotify/eslint-config-base/-/eslint-config-base-13.0.1.tgz#91471028de6426a1f1a5cc06aa9aeb6d8c85565f"
integrity sha512-7dC5zMJpNud9UBCHVk/IWfZOXKyuRkcyopHzTJi3xsfmZcZvi0jTSVIf7sv8315lpjmqroVZoUdKbxZFkZcZpA==
"@spotify/eslint-config-base@^14.0.0":
version "14.0.1"
resolved "https://registry.npmjs.org/@spotify/eslint-config-base/-/eslint-config-base-14.0.1.tgz#a67a1aff30e20ce6f5d83895d52609af18d7d33f"
integrity sha512-wT3ejMg81CrOhrGlt2HwqgiDQI7mdY3AkzfhR+AlZZM9FFL+7QEvQYeejlfATu2UPOJbEU8C1WsL9XMKKlC+8g==
"@spotify/eslint-config-react@^13.0.0":
version "13.0.1"
resolved "https://registry.npmjs.org/@spotify/eslint-config-react/-/eslint-config-react-13.0.1.tgz#f309f5d3c53ef1e2c7c6ce05f76ee681970112c3"
integrity sha512-gyC0CtJ2H9K57HyQG5/RcMsJiB6qmVbBHOHWukZcPLfYtwkK201kgMjHrVfJXoSN+mJxcWhDVPxqe+eA7LHshQ==
"@spotify/eslint-config-react@^14.0.0":
version "14.0.1"
resolved "https://registry.npmjs.org/@spotify/eslint-config-react/-/eslint-config-react-14.0.1.tgz#8269c4c4267e8cec8d7e2252b65831651aa31023"
integrity sha512-Ap3gLGoKsvX4WtclaBaLKVpmnOU2G52k/2c0C1XO98Vix1gBmN1aR2ZMrfv1qq+W7P6LsPt/+YQfkT8M1qNaxQ==
"@spotify/eslint-config-typescript@^13.0.0":
version "13.0.1"
resolved "https://registry.npmjs.org/@spotify/eslint-config-typescript/-/eslint-config-typescript-13.0.1.tgz#47801a66d5569074a110f4422eba60aafc6bd7f8"
integrity sha512-1wLQFyN2H2v+rn/mytA2PGzmGxOmdZdcKBpNyW+4z0qJydpvavp2SeBj/X+FEbwKoYBoUdG9QLr40eLQh1ZHZA==
"@spotify/eslint-config-typescript@^14.0.0":
version "14.0.1"
resolved "https://registry.npmjs.org/@spotify/eslint-config-typescript/-/eslint-config-typescript-14.0.1.tgz#850a435b0defebbb3de591d83e3fc369bbc51753"
integrity sha512-y/8on49Wtg3HvKd9A32Q7iJaOgngcSJR8hjGx/POFhJFcPRcZuTJSlhd31CF8fg78bMuzdvYH8au7FhNKjnEVw==
"@spotify/prettier-config@^13.0.1":
version "13.0.1"
resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-13.0.1.tgz#0fdceb3d4ab543259ce6adc0ec1d10e34898b812"
integrity sha512-oVd4hjx2+y0MeUdk1l+ItwVLwlrDlvTlGwXBWMMzPYc7DLyxuxFvDfoHGkAQkrikfAgtdnzxrW6u9a8ywUqdfw==
"@spotify/prettier-config@^14.0.0":
version "14.0.1"
resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-14.0.1.tgz#a3a2342ec07693647ab76a64a623fbb79d464fa7"
@@ -6208,7 +6461,7 @@
resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.3.1.tgz#21a285dbffdce9567c437ebf0d081bf9210807e6"
integrity sha512-cZ8Tr6ZAWNUFfDeCKn/pGi976iWSkS8ijmEYKosP+6ktdZ7lW9HVLHojyusPw3w0j8PI4VBeWAXAmi/2G7owxw==
"@svgr/babel-preset@^6.3.1":
"@svgr/babel-preset@^6.2.0", "@svgr/babel-preset@^6.3.1":
version "6.3.1"
resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.3.1.tgz#8bd1ead79637d395e9362b01dd37cfd59702e152"
integrity sha512-tQtWtzuMMQ3opH7je+MpwfuRA1Hf3cKdSgTtAYwOBDfmhabP7rcTfBi3E7V3MuwJNy/Y02/7/RutvwS1W4Qv9g==
@@ -6222,7 +6475,7 @@
"@svgr/babel-plugin-transform-react-native-svg" "^6.3.1"
"@svgr/babel-plugin-transform-svg-component" "^6.3.1"
"@svgr/core@^6.3.1":
"@svgr/core@^6.2.1", "@svgr/core@^6.3.1":
version "6.3.1"
resolved "https://registry.npmjs.org/@svgr/core/-/core-6.3.1.tgz#752adf49d8d5473b15d76ca741961de093f715bd"
integrity sha512-Sm3/7OdXbQreemf9aO25keerZSbnKMpGEfmH90EyYpj1e8wMD4TuwJIb3THDSgRMWk1kYJfSRulELBy4gVgZUA==
@@ -6231,7 +6484,7 @@
camelcase "^6.2.0"
cosmiconfig "^7.0.1"
"@svgr/hast-util-to-babel-ast@^6.3.1":
"@svgr/hast-util-to-babel-ast@^6.2.1", "@svgr/hast-util-to-babel-ast@^6.3.1":
version "6.3.1"
resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.3.1.tgz#59614e24d2a4a28010e02089213b3448d905769d"
integrity sha512-NgyCbiTQIwe3wHe/VWOUjyxmpUmsrBjdoIxKpXt3Nqc3TN30BpJG22OxBvVzsAh9jqep0w0/h8Ywvdk3D9niNQ==
@@ -6239,7 +6492,17 @@
"@babel/types" "^7.18.4"
entities "^4.3.0"
"@svgr/plugin-jsx@6.3.x", "@svgr/plugin-jsx@^6.3.1":
"@svgr/plugin-jsx@6.2.x":
version "6.2.1"
resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.2.1.tgz#5668f1d2aa18c2f1bb7a1fc9f682d3f9aed263bd"
integrity sha512-u+MpjTsLaKo6r3pHeeSVsh9hmGRag2L7VzApWIaS8imNguqoUwDq/u6U/NDmYs/KAsrmtBjOEaAAPbwNGXXp1g==
dependencies:
"@babel/core" "^7.15.5"
"@svgr/babel-preset" "^6.2.0"
"@svgr/hast-util-to-babel-ast" "^6.2.1"
svg-parser "^2.0.2"
"@svgr/plugin-jsx@6.3.x", "@svgr/plugin-jsx@^6.2.1", "@svgr/plugin-jsx@^6.3.1":
version "6.3.1"
resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.3.1.tgz#de7b2de824296b836d6b874d498377896e367f50"
integrity sha512-r9+0mYG3hD4nNtUgsTXWGYJomv/bNd7kC16zvsM70I/bGeoCi/3lhTmYqeN6ChWX317OtQCSZZbH4wq9WwoXbw==
@@ -6249,7 +6512,16 @@
"@svgr/hast-util-to-babel-ast" "^6.3.1"
svg-parser "^2.0.4"
"@svgr/plugin-svgo@6.3.x", "@svgr/plugin-svgo@^6.3.1":
"@svgr/plugin-svgo@6.2.x":
version "6.2.0"
resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.2.0.tgz#4cbe6a33ccccdcae4e3b63ded64cc1cbe1faf48c"
integrity sha512-oDdMQONKOJEbuKwuy4Np6VdV6qoaLLvoY86hjvQEgU82Vx1MSWRyYms6Sl0f+NtqxLI/rDVufATbP/ev996k3Q==
dependencies:
cosmiconfig "^7.0.1"
deepmerge "^4.2.2"
svgo "^2.5.0"
"@svgr/plugin-svgo@6.3.x", "@svgr/plugin-svgo@^6.2.0", "@svgr/plugin-svgo@^6.3.1":
version "6.3.1"
resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.3.1.tgz#3c1ff2efaed10e5c5d35a6cae7bacaedc18b5d4a"
integrity sha512-yJIjTDKPYqzFVjmsbH5EdIwEsmKxjxdXSGJVLeUgwZOZPAkNQmD1v7LDbOdOKbR44FG8465Du+zWPdbYGnbMbw==
@@ -6258,6 +6530,21 @@
deepmerge "^4.2.2"
svgo "^2.8.0"
"@svgr/rollup@6.2.x":
version "6.2.1"
resolved "https://registry.npmjs.org/@svgr/rollup/-/rollup-6.2.1.tgz#23ac3173d2bd85842ca8858d3435332af1f064ab"
integrity sha512-5X6aMiGL1F5g0TubLY41GJ/Qf0Kz2xtbF37UbRJEHe2Z9CMlGl9Z3fQ8e28vmHrTptmymNRoHssgQ2Ejb1DARQ==
dependencies:
"@babel/core" "^7.15.5"
"@babel/plugin-transform-react-constant-elements" "^7.14.5"
"@babel/preset-env" "^7.15.6"
"@babel/preset-react" "^7.14.5"
"@babel/preset-typescript" "^7.16.0"
"@svgr/core" "^6.2.1"
"@svgr/plugin-jsx" "^6.2.1"
"@svgr/plugin-svgo" "^6.2.0"
rollup-pluginutils "^2.8.2"
"@svgr/rollup@6.3.x":
version "6.3.1"
resolved "https://registry.npmjs.org/@svgr/rollup/-/rollup-6.3.1.tgz#cf59c39f1f145383dfdeea7068ec18149360668e"
@@ -6273,6 +6560,20 @@
"@svgr/plugin-jsx" "^6.3.1"
"@svgr/plugin-svgo" "^6.3.1"
"@svgr/webpack@6.2.x":
version "6.2.1"
resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.2.1.tgz#ef5d51c1b6be4e7537fb9f76b3f2b2e22b63c58d"
integrity sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw==
dependencies:
"@babel/core" "^7.15.5"
"@babel/plugin-transform-react-constant-elements" "^7.14.5"
"@babel/preset-env" "^7.15.6"
"@babel/preset-react" "^7.14.5"
"@babel/preset-typescript" "^7.15.0"
"@svgr/core" "^6.2.1"
"@svgr/plugin-jsx" "^6.2.1"
"@svgr/plugin-svgo" "^6.2.0"
"@svgr/webpack@6.3.x":
version "6.3.1"
resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.3.1.tgz#001d03236ebb03bf47c0a4b92d5423e05095ebe6"
@@ -13105,6 +13406,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
"@backstage/plugin-gcalendar" "^0.3.4-next.0"
"@backstage/plugin-gcp-projects" "^0.3.27-next.0"
"@backstage/plugin-github-actions" "^0.5.8-next.0"
"@backstage/plugin-github-issues" "^0.0.0"
"@backstage/plugin-gocd" "^0.1.14-next.0"
"@backstage/plugin-graphiql" "^0.2.40-next.0"
"@backstage/plugin-home" "^0.4.24-next.0"
@@ -18111,6 +18413,11 @@ luxon@^1.23.x:
resolved "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz#e7f96daad3938c06a62de0fb027115d251251fbf"
integrity sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==
luxon@^2.4.0:
version "2.5.0"
resolved "https://registry.npmjs.org/luxon/-/luxon-2.5.0.tgz#098090f67d690b247e83c090267a60b1aa8ea96c"
integrity sha512-IDkEPB80Rb6gCAU+FEib0t4FeJ4uVOuX1CQ9GsvU3O+JAGIgu0J7sf1OarXKaKDygTZIoJyU6YdZzTFRu+YR0A==
luxon@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/luxon/-/luxon-3.0.1.tgz#6901111d10ad06fd267ad4e4128a84bef8a77299"
@@ -19250,6 +19557,32 @@ msw@^0.39.2:
type-fest "^1.2.2"
yargs "^17.3.1"
msw@^0.42.0:
version "0.42.3"
resolved "https://registry.npmjs.org/msw/-/msw-0.42.3.tgz#150c475e2cb6d53c67503bd0e3f6251bfd075328"
integrity sha512-zrKBIGCDsNUCZLd3DLSeUtRruZ0riwJgORg9/bSDw3D0PTI8XUGAK3nC0LJA9g0rChGuKaWK/SwObA8wpFrz4g==
dependencies:
"@mswjs/cookies" "^0.2.0"
"@mswjs/interceptors" "^0.16.3"
"@open-draft/until" "^1.0.3"
"@types/cookie" "^0.4.1"
"@types/js-levenshtein" "^1.1.1"
chalk "4.1.1"
chokidar "^3.4.2"
cookie "^0.4.2"
graphql "^16.3.0"
headers-polyfill "^3.0.4"
inquirer "^8.2.0"
is-node-process "^1.0.1"
js-levenshtein "^1.1.6"
node-fetch "^2.6.7"
outvariant "^1.3.0"
path-to-regexp "^6.2.0"
statuses "^2.0.0"
strict-event-emitter "^0.2.0"
type-fest "^1.2.2"
yargs "^17.3.1"
msw@^0.43.0:
version "0.43.1"
resolved "https://registry.npmjs.org/msw/-/msw-0.43.1.tgz#57cb4af56f07442e8a6d14d76032a0ab41434256"
@@ -21449,7 +21782,7 @@ prettier@^1.16.4, prettier@^1.19.1:
resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
prettier@^2.2.1:
prettier@^2.2.1, prettier@^2.7.1:
version "2.7.1"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
@@ -23242,6 +23575,11 @@ run-parallel@^1.1.9:
resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
run-script-webpack-plugin@^0.0.14:
version "0.0.14"
resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.0.14.tgz#fe2362b32c1dab7a8af7a6f1246fc043690cedd7"
integrity sha512-DXe6lzzEVXjBr/74zd4m4yOfmz5P6GMjzhQxDDsViOmwG7cap8UCE6RgD5rT7zf4wM83a+ToHnpB3v4efUv5IA==
run-script-webpack-plugin@^0.1.0:
version "0.1.1"
resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.1.1.tgz#dad3114be32eb864d2160306e4d9c52a2c1cfd59"
@@ -24684,12 +25022,12 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
svg-parser@^2.0.4:
svg-parser@^2.0.2, svg-parser@^2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5"
integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==
svgo@^2.7.0, svgo@^2.8.0:
svgo@^2.5.0, svgo@^2.7.0, svgo@^2.8.0:
version "2.8.0"
resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==