diff --git a/plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx b/plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx
deleted file mode 100644
index 547e32db22..0000000000
--- a/plugins/github-issues/src/hooks/useGetIssuesBeRepoFromGitHub.test.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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(() => ({}));
-jest.mock('./useOctokitGraphQL', () => ({
- useOctokitGraphQL: jest.fn(() => mockGraphQLQuery),
-}));
-
-import React from 'react';
-import { render } from '@testing-library/react';
-import { useGetIssuesByRepoFromGitHub } from './useGetIssuesByRepoFromGitHub';
-
-describe('useGetIssuesBeRepoFromGitHub', () => {
- it('should call GitHub API with correct query with fragment for each repo', async () => {
- const Helper = () => {
- const getIssues = useGetIssuesByRepoFromGitHub();
-
- getIssues(['mrwolny/yo-yo', 'mrwolny/yoyo', 'mrwolny/yo.yo'], 10);
-
- return
;
- };
-
- render();
-
- expect(mockGraphQLQuery).toHaveBeenCalledTimes(1);
- expect(mockGraphQLQuery).toHaveBeenCalledWith(
- '\n' +
- ' \n' +
- ' fragment issues on Repository {\n' +
- ' issues(\n' +
- ' states: OPEN\n' +
- ' first: 10\n' +
- ' orderBy: { field: UPDATED_AT, direction: DESC }\n' +
- ' ) {\n' +
- ' totalCount\n' +
- ' edges {\n' +
- ' node {\n' +
- ' assignees(first: 10) {\n' +
- ' edges {\n' +
- ' node {\n' +
- ' avatarUrl\n' +
- ' login\n' +
- ' }\n' +
- ' }\n' +
- ' }\n' +
- ' author {\n' +
- ' login\n' +
- ' avatarUrl\n' +
- ' url\n' +
- ' }\n' +
- ' repository {\n' +
- ' nameWithOwner\n' +
- ' }\n' +
- ' title\n' +
- ' url\n' +
- ' participants {\n' +
- ' totalCount\n' +
- ' }\n' +
- ' updatedAt\n' +
- ' createdAt\n' +
- ' comments(last: 1) {\n' +
- ' totalCount\n' +
- ' }\n' +
- ' }\n' +
- ' }\n' +
- ' }\n' +
- ' }\n' +
- ' \n' +
- '\n' +
- ' query {\n' +
- ' \n' +
- ' yoyo: repository(name: "yo-yo", owner: "mrwolny") {\n' +
- ' ...issues\n' +
- ' }\n' +
- ' ,\n' +
- ' yoyox: repository(name: "yoyo", owner: "mrwolny") {\n' +
- ' ...issues\n' +
- ' }\n' +
- ' ,\n' +
- ' yoyoxx: repository(name: "yo.yo", owner: "mrwolny") {\n' +
- ' ...issues\n' +
- ' }\n' +
- ' \n' +
- ' } \n' +
- ' ',
- );
- });
-});
diff --git a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts
index 271cd6c741..29e89213dc 100644
--- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts
+++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts
@@ -13,161 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
-import { useOctokitGraphQL } from './useOctokitGraphQL';
+import { useApi } from '@backstage/core-plugin-api';
-type Assignee = {
- avatarUrl: string;
- login: string;
-};
+import { useAsyncRetry } from 'react-use';
+import { gitHubIssuesApiRef } from '../api';
-export type EdgesWithNodes = {
- edges: Array<{
- node: T;
- }>;
-};
-
-export type Node = {
- node: T;
-};
-
-type IssueAuthor = {
- login: string;
-};
-
-export type Issue = {
- assignees: EdgesWithNodes;
- author: IssueAuthor;
- repository: {
- nameWithOwner: string;
- };
- title: string;
- url: string;
- participants: {
- totalCount: number;
- };
- createdAt: string;
- updatedAt: string;
- comments: {
- totalCount: number;
- };
-};
-
-export type RepoIssues = {
- issues: {
- totalCount: number;
- } & EdgesWithNodes;
-};
-
-export type RepoIssuesQueryResults = Record;
-
-const createQuery = (
- repositories: Array<{
- safeName: string;
- name: string;
- owner: string;
- }>,
+export const useGetIssuesByRepoFromGitHub = (
+ repos: Array,
itemsPerRepo: number,
-): string => {
- const fragment = `
- fragment issues on Repository {
- issues(
- states: OPEN
- first: ${itemsPerRepo}
- orderBy: { field: UPDATED_AT, direction: DESC }
- ) {
- totalCount
- edges {
- node {
- assignees(first: 10) {
- edges {
- node {
- avatarUrl
- login
- }
- }
- }
- author {
- login
- avatarUrl
- url
- }
- repository {
- nameWithOwner
- }
- title
- url
- participants {
- totalCount
- }
- updatedAt
- createdAt
- comments(last: 1) {
- totalCount
- }
- }
- }
- }
- }
- `;
+) => {
+ const gitHubIssuesApi = useApi(gitHubIssuesApiRef);
- const query = `
- ${fragment}
-
- query {
- ${repositories.map(
- ({ safeName, name, owner }) => `
- ${safeName}: repository(name: "${name}", owner: "${owner}") {
- ...issues
- }
- `,
- )}
- }
- `;
-
- return query;
-};
-
-export const useGetIssuesByRepoFromGitHub = () => {
- const graphql = useOctokitGraphQL();
-
- const fn = React.useRef(
- async (
- repos: Array,
- itemsPerRepo: number,
- ): Promise> => {
- const safeNames: Array = [];
-
- 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),
+ const {
+ value: issues,
+ loading: isLoading,
+ retry,
+ } = useAsyncRetry(async () => {
+ if (repos.length > 0) {
+ return await gitHubIssuesApi.fetchIssuesByRepoFromGitHub(
+ repos,
+ itemsPerRepo,
);
+ }
- return repositories.reduce((acc, { safeName, name, owner }) => {
- acc[`${owner}/${name}`] = issuesByRepo[safeName];
+ return {};
+ }, [repos]);
- return acc;
- }, {} as Record);
- },
- );
-
- return fn.current;
+ return { isLoading, gitHubIssuesByRepo: issues, retry };
};
diff --git a/plugins/github-issues/src/hooks/useOctokitGraphQL.ts b/plugins/github-issues/src/hooks/useOctokitGraphQL.ts
deleted file mode 100644
index 6b783efd6f..0000000000
--- a/plugins/github-issues/src/hooks/useOctokitGraphQL.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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';
-import {
- useApi,
- githubAuthApiRef,
- configApiRef,
-} from '@backstage/core-plugin-api';
-import { readGitHubIntegrationConfigs } from '@backstage/integration';
-
-let octokit: Octokit;
-
-export const useOctokitGraphQL = () => {
- const auth = useApi(githubAuthApiRef);
- const config = useApi(configApiRef);
-
- const baseUrl = readGitHubIntegrationConfigs(
- config.getOptionalConfigArray('integrations.github') ?? [],
- )[0].apiBaseUrl;
-
- return (path: string, options?: any): Promise =>
- auth
- .getAccessToken(['repo'])
- .then((token: string) => {
- if (!octokit) {
- octokit = new Octokit({ auth: token, ...(baseUrl && { baseUrl }) });
- }
-
- return octokit;
- })
- .then(octokitInstance => {
- return octokitInstance.graphql(path, options);
- });
-};