diff --git a/app-config.yaml b/app-config.yaml
index 22ca1fcaff..8dacce900c 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -300,7 +300,7 @@ auth:
development:
clientId: ${AUTH_GITHUB_CLIENT_ID}
clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
- enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL}
+ # enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL}
gitlab:
development:
clientId: ${AUTH_GITLAB_CLIENT_ID}
diff --git a/packages/app/package.json b/packages/app/package.json
index 4181b036e9..ade10e9c14 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -33,6 +33,7 @@
"@backstage/plugin-gcalendar": "workspace:^",
"@backstage/plugin-gcp-projects": "workspace:^",
"@backstage/plugin-github-actions": "workspace:^",
+ "@backstage/plugin-github-issues": "workspace:^",
"@backstage/plugin-gocd": "workspace:^",
"@backstage/plugin-graphiql": "workspace:^",
"@backstage/plugin-home": "workspace:^",
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index c2f297a2d7..4cf6779607 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -153,6 +153,8 @@ import {
ReportIssue,
} from '@backstage/plugin-techdocs-module-addons-contrib';
+import { GitHubIssuesCard } from '@backstage/plugin-github-issues';
+
const customEntityFilterKind = ['Component', 'API', 'System'];
const EntityLayoutWrapper = (props: { children?: ReactNode }) => {
@@ -342,6 +344,10 @@ const overviewContent = (
+
+
+
+
diff --git a/plugins/github-issues/src/api/gitHubIssuesApi.ts b/plugins/github-issues/src/api/gitHubIssuesApi.ts
index 816345940c..a07e4f5790 100644
--- a/plugins/github-issues/src/api/gitHubIssuesApi.ts
+++ b/plugins/github-issues/src/api/gitHubIssuesApi.ts
@@ -22,6 +22,7 @@ import {
} from '@backstage/core-plugin-api';
import { readGitHubIntegrationConfigs } from '@backstage/integration';
import { ForwardedError } from '@backstage/errors';
+import { IssuesByRepoOptions, IssuesFilters } from '../types';
/** @internal */
export type Assignee = {
@@ -103,6 +104,13 @@ export const gitHubIssuesApi = (
const fetchIssuesByRepoFromGitHub = async (
repos: Array,
itemsPerRepo: number,
+ {
+ filterBy,
+ orderBy = {
+ field: 'UPDATED_AT',
+ direction: 'DESC',
+ },
+ }: IssuesByRepoOptions = {},
): Promise => {
const graphql = await getOctokit();
const safeNames: Array = [];
@@ -126,10 +134,17 @@ export const gitHubIssuesApi = (
};
});
+ // eslint-disable-next-line no-console
+ console.log(`
+ ---------------------------------------------------
+ ${createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy })}
+ ---------------------------------------------------
+ `);
+
let issuesByRepo: IssuesByRepo = {};
try {
issuesByRepo = await graphql(
- createIssueByRepoQuery(repositories, itemsPerRepo),
+ createIssueByRepoQuery(repositories, itemsPerRepo, { filterBy }),
);
} catch (e) {
if (e.data) {
@@ -151,6 +166,34 @@ export const gitHubIssuesApi = (
return { fetchIssuesByRepoFromGitHub };
};
+function formatFilterValue(value: IssuesFilters[keyof IssuesFilters]): string {
+ if (Array.isArray(value)) {
+ return `[ ${value.map(formatFilterValue).join(', ')}`;
+ }
+
+ return typeof value === 'string' ? `\"${value}\"` : `${value}`;
+}
+
+function createFilterByClause(filterBy?: IssuesFilters): string {
+ if (typeof filterBy === 'undefined') {
+ return '';
+ }
+
+ return Object.entries(filterBy)
+ .flatMap(([field, value]) => {
+ if (typeof value === 'undefined') {
+ return [];
+ }
+
+ if (field === 'states') {
+ return [`${field}: ${value.join(', ')}`];
+ }
+
+ return [`${field}: ${formatFilterValue}`];
+ })
+ .join(', ');
+}
+
function createIssueByRepoQuery(
repositories: Array<{
safeName: string;
@@ -158,13 +201,15 @@ function createIssueByRepoQuery(
owner: string;
}>,
itemsPerRepo: number,
+ { filterBy, orderBy }: IssuesByRepoOptions,
): string {
const fragment = `
fragment issues on Repository {
issues(
states: OPEN
first: ${itemsPerRepo}
- orderBy: { field: UPDATED_AT, direction: DESC }
+ filterBy: { ${createFilterByClause(filterBy)} }
+ orderBy: { field: ${orderBy?.field}, direction: ${orderBy?.direction} }
) {
totalCount
edges {
diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx
index 574c15d3b3..78cdfbd708 100644
--- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx
+++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx
@@ -24,6 +24,7 @@ import { useGetIssuesByRepoFromGitHub } from '../../hooks/useGetIssuesByRepoFrom
import { IssuesList } from './IssuesList';
import { NoRepositoriesInfo } from './NoRepositoriesInfo';
+import { IssuesByRepoOptions } from '../../types';
/**
* @public
@@ -31,17 +32,18 @@ import { NoRepositoriesInfo } from './NoRepositoriesInfo';
export type GitHubIssuesProps = {
itemsPerPage?: number;
itemsPerRepo?: number;
+ queryOptions?: IssuesByRepoOptions;
};
export const GitHubIssues = (props: GitHubIssuesProps) => {
- const { itemsPerPage = 10, itemsPerRepo = 40 } = props;
+ const { itemsPerPage = 10, itemsPerRepo = 40, queryOptions } = props;
const { repositories } = useEntityGitHubRepositories();
const {
isLoading,
gitHubIssuesByRepo: issuesByRepository,
retry,
- } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo);
+ } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo, queryOptions);
if (!repositories.length) {
return ;
diff --git a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts
index 8d1d0c2056..ab9305693d 100644
--- a/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts
+++ b/plugins/github-issues/src/hooks/useGetIssuesByRepoFromGitHub.ts
@@ -17,10 +17,12 @@ import { useApi } from '@backstage/core-plugin-api';
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
import { gitHubIssuesApiRef } from '../api';
+import { IssuesByRepoOptions } from '../types';
export const useGetIssuesByRepoFromGitHub = (
repos: Array,
itemsPerRepo: number,
+ options?: IssuesByRepoOptions,
) => {
const gitHubIssuesApi = useApi(gitHubIssuesApiRef);
@@ -33,6 +35,7 @@ export const useGetIssuesByRepoFromGitHub = (
return await gitHubIssuesApi.fetchIssuesByRepoFromGitHub(
repos,
itemsPerRepo,
+ options,
);
}
diff --git a/plugins/github-issues/src/types.ts b/plugins/github-issues/src/types.ts
new file mode 100644
index 0000000000..ee245929b8
--- /dev/null
+++ b/plugins/github-issues/src/types.ts
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+type IssueState = 'OPEN' | 'CLOSED';
+
+/** @internal */
+export interface IssuesFilters {
+ assignee?: string;
+ createdBy?: string;
+ labels?: string[];
+ mentioned?: string;
+ milestone?: string;
+ states?: IssueState[];
+}
+
+export interface IssuesByRepoOptions {
+ filterBy?: IssuesFilters;
+ orderBy?: {
+ field: 'CREATED_AT' | 'UPDATED_AT' | 'COMMENTS';
+ direction: 'ASC' | 'DESC';
+ };
+}
diff --git a/query.graphql b/query.graphql
new file mode 100644
index 0000000000..98a72fac26
--- /dev/null
+++ b/query.graphql
@@ -0,0 +1,77 @@
+/* http://localhost:7007/api/auth/github /*
+
+{
+ repository(owner: "backstage", name: "backstage") {
+ issues(first: 1, filterBy: { labels: ["bug"] }) {
+ nodes {
+ title
+ body
+ bodyHTML
+ bodyText
+ number
+ labels(first: 100) {
+ nodes {
+ color
+ name
+ id
+ }
+ }
+ author {
+ url
+ avatarUrl
+ login
+ }
+ }
+ }
+ }
+}
+
+
+
+fragment issues on Repository {
+ issues(
+ states: OPEN
+ first: 40
+ orderBy: { field: UPDATED_AT, direction: DESC }
+ ) {
+ totalCount
+ edges {
+ node {
+ assignees(first: 10) {
+ edges {
+ node {
+ avatarUrl
+ login
+ }
+ }
+ }
+ author {
+ login
+ }
+ repository {
+ nameWithOwner
+ }
+ title
+ url
+ participants {
+ totalCount
+ }
+ updatedAt
+ createdAt
+ comments(last: 1) {
+ totalCount
+ }
+ }
+ }
+ }
+}
+
+
+query {
+
+ backstage: repository(name: "backstage", owner: "backstage") {
+ ...issues
+ }
+
+}
+
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index e5f10c942a..1df05d3c22 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5604,7 +5604,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@backstage/plugin-github-issues@workspace:plugins/github-issues":
+"@backstage/plugin-github-issues@workspace:^, @backstage/plugin-github-issues@workspace:plugins/github-issues":
version: 0.0.0-use.local
resolution: "@backstage/plugin-github-issues@workspace:plugins/github-issues"
dependencies:
@@ -22004,6 +22004,7 @@ __metadata:
"@backstage/plugin-gcalendar": "workspace:^"
"@backstage/plugin-gcp-projects": "workspace:^"
"@backstage/plugin-github-actions": "workspace:^"
+ "@backstage/plugin-github-issues": "workspace:^"
"@backstage/plugin-gocd": "workspace:^"
"@backstage/plugin-graphiql": "workspace:^"
"@backstage/plugin-home": "workspace:^"