diff --git a/.changeset/silly-dryers-smile.md b/.changeset/silly-dryers-smile.md
new file mode 100644
index 0000000000..7337651532
--- /dev/null
+++ b/.changeset/silly-dryers-smile.md
@@ -0,0 +1,58 @@
+---
+'@backstage/plugin-azure-devops': patch
+'@backstage/plugin-azure-devops-backend': patch
+'@backstage/plugin-azure-devops-common': patch
+---
+
+Created some initial filters that can be used to create pull request columns:
+
+- All
+- AssignedToUser
+- AssignedToCurrentUser
+- AssignedToTeam
+- AssignedToTeams
+- AssignedToCurrentUsersTeams
+- CreatedByUser
+- CreatedByCurrentUser
+- CreatedByTeam
+- CreatedByTeams
+- CreatedByCurrentUsersTeams
+
+Example custom column creation:
+
+```tsx
+const COLUMN_CONFIGS: PullRequestColumnConfig[] = [
+ {
+ title: 'Created by me',
+ filters: [{ type: FilterType.CreatedByCurrentUser }],
+ },
+ {
+ title: 'Created by Backstage Core',
+ filters: [
+ {
+ type: FilterType.CreatedByTeam,
+ teamName: 'Backstage Core',
+ },
+ ],
+ },
+ {
+ title: 'Assigned to my teams',
+ filters: [{ type: FilterType.AssignedToCurrentUsersTeams }],
+ },
+ {
+ title: 'Other PRs',
+ filters: [{ type: FilterType.All }],
+ simplified: true,
+ },
+];
+
+
+ }
+/>;
+```
diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts
index aa843e9c17..7a0d0a279e 100644
--- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts
+++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts
@@ -215,6 +215,7 @@ function convertReviewer(
return {
id: identityRef.id,
displayName: identityRef.displayName,
+ uniqueName: identityRef.uniqueName,
imageUrl: getAvatarUrl(identityRef),
isRequired: identityRef.isRequired,
isContainer: identityRef.isContainer,
diff --git a/plugins/azure-devops-common/api-report.md b/plugins/azure-devops-common/api-report.md
index bb458f169a..85a9e54847 100644
--- a/plugins/azure-devops-common/api-report.md
+++ b/plugins/azure-devops-common/api-report.md
@@ -61,6 +61,10 @@ export interface CreatedBy {
// (undocumented)
imageUrl?: string;
// (undocumented)
+ teamIds?: string[];
+ // (undocumented)
+ teamNames?: string[];
+ // (undocumented)
uniqueName?: string;
}
@@ -254,6 +258,8 @@ export interface Reviewer {
// (undocumented)
isRequired?: boolean;
// (undocumented)
+ uniqueName?: string;
+ // (undocumented)
voteStatus: PullRequestVoteStatus;
}
diff --git a/plugins/azure-devops-common/src/types.ts b/plugins/azure-devops-common/src/types.ts
index e6bd174079..0befcf0b60 100644
--- a/plugins/azure-devops-common/src/types.ts
+++ b/plugins/azure-devops-common/src/types.ts
@@ -145,6 +145,7 @@ export interface DashboardPullRequest {
export interface Reviewer {
id?: string;
displayName?: string;
+ uniqueName?: string;
imageUrl?: string;
isRequired?: boolean;
isContainer?: boolean;
@@ -164,6 +165,8 @@ export interface CreatedBy {
displayName?: string;
uniqueName?: string;
imageUrl?: string;
+ teamIds?: string[];
+ teamNames?: string[];
}
export interface Repository {
diff --git a/plugins/azure-devops/api-report.md b/plugins/azure-devops/api-report.md
index 0f3e3310ef..11e238e6f5 100644
--- a/plugins/azure-devops/api-report.md
+++ b/plugins/azure-devops/api-report.md
@@ -6,9 +6,55 @@
///
import { BackstagePlugin } from '@backstage/core-plugin-api';
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
import { Entity } from '@backstage/catalog-model';
import { SvgIconProps } from '@material-ui/core';
+// Warning: (ae-missing-release-tag) "AllFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type AllFilter = BaseFilter & {
+ type: FilterType.All;
+};
+
+// Warning: (ae-missing-release-tag) "AssignedToTeamFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type AssignedToTeamFilter = BaseFilter & {
+ type: FilterType.AssignedToTeam;
+ teamId: string;
+};
+
+// Warning: (ae-missing-release-tag) "AssignedToTeamsFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type AssignedToTeamsFilter = BaseFilter &
+ (
+ | {
+ type: FilterType.AssignedToTeams;
+ teamIds: string[];
+ }
+ | {
+ type: FilterType.AssignedToCurrentUsersTeams;
+ teamIds?: string[];
+ }
+ );
+
+// Warning: (ae-missing-release-tag) "AssignedToUserFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type AssignedToUserFilter = BaseFilter &
+ (
+ | {
+ type: FilterType.AssignedToUser;
+ email: string;
+ }
+ | {
+ type: FilterType.AssignedToCurrentUser;
+ email?: string;
+ }
+ );
+
// Warning: (ae-missing-release-tag) "azureDevOpsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -25,11 +71,71 @@ export const AzurePullRequestsIcon: (props: SvgIconProps) => JSX.Element;
export const AzurePullRequestsPage: ({
projectName,
pollingInterval,
+ defaultColumnConfigs,
}: {
projectName?: string | undefined;
pollingInterval?: number | undefined;
+ defaultColumnConfigs?: PullRequestColumnConfig[] | undefined;
}) => JSX.Element;
+// Warning: (ae-missing-release-tag) "BaseFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type BaseFilter = {
+ type: FilterType;
+};
+
+// Warning: (ae-missing-release-tag) "CreatedByTeamFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type CreatedByTeamFilter = BaseFilter &
+ ({
+ type: FilterType.CreatedByTeam;
+ } & (
+ | {
+ teamId: string;
+ }
+ | {
+ teamName: string;
+ }
+ ));
+
+// Warning: (ae-missing-release-tag) "CreatedByTeamsFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type CreatedByTeamsFilter = BaseFilter &
+ (
+ | ({
+ type: FilterType.CreatedByTeams;
+ } & (
+ | {
+ teamIds: string[];
+ }
+ | {
+ teamNames: string[];
+ }
+ ))
+ | {
+ type: FilterType.CreatedByCurrentUsersTeams;
+ teamIds?: string[];
+ }
+ );
+
+// Warning: (ae-missing-release-tag) "CreatedByUserFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type CreatedByUserFilter = BaseFilter &
+ (
+ | {
+ type: FilterType.CreatedByUser;
+ email: string;
+ }
+ | {
+ type: FilterType.CreatedByCurrentUser;
+ email?: string;
+ }
+ );
+
// Warning: (ae-missing-release-tag) "EntityAzurePipelinesContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -48,10 +154,67 @@ export const EntityAzurePullRequestsContent: ({
defaultLimit?: number | undefined;
}) => JSX.Element;
+// Warning: (ae-missing-release-tag) "Filter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type Filter =
+ | AssignedToUserFilter
+ | CreatedByUserFilter
+ | AssignedToTeamFilter
+ | CreatedByTeamFilter
+ | AssignedToTeamsFilter
+ | CreatedByTeamsFilter
+ | AllFilter;
+
+// Warning: (ae-missing-release-tag) "FilterType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export enum FilterType {
+ // (undocumented)
+ All = 'All',
+ // (undocumented)
+ AssignedToCurrentUser = 'AssignedToCurrentUser',
+ // (undocumented)
+ AssignedToCurrentUsersTeams = 'AssignedToCurrentUsersTeams',
+ // (undocumented)
+ AssignedToTeam = 'AssignedToTeam',
+ // (undocumented)
+ AssignedToTeams = 'AssignedToTeams',
+ // (undocumented)
+ AssignedToUser = 'AssignedToUser',
+ // (undocumented)
+ CreatedByCurrentUser = 'CreatedByCurrentUser',
+ // (undocumented)
+ CreatedByCurrentUsersTeams = 'CreatedByCurrentUsersTeams',
+ // (undocumented)
+ CreatedByTeam = 'CreatedByTeam',
+ // (undocumented)
+ CreatedByTeams = 'CreatedByTeams',
+ // (undocumented)
+ CreatedByUser = 'CreatedByUser',
+}
+
// Warning: (ae-missing-release-tag) "isAzureDevOpsAvailable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const isAzureDevOpsAvailable: (entity: Entity) => boolean;
+// Warning: (ae-missing-release-tag) "PullRequestColumnConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export interface PullRequestColumnConfig {
+ // (undocumented)
+ filters: Filter[];
+ // (undocumented)
+ simplified?: boolean;
+ // (undocumented)
+ title: string;
+}
+
+// Warning: (ae-missing-release-tag) "PullRequestFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean;
+
// (No @packageDocumentation comment for this package)
```
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx b/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx
index 9f21c4b81b..158c4bca5b 100644
--- a/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx
+++ b/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx
@@ -21,56 +21,17 @@ import {
Progress,
ResponseErrorPanel,
} from '@backstage/core-components';
-import { PullRequestGroup, PullRequestGroupConfig } from './lib/types';
-import React, { useEffect, useState } from 'react';
-import { getCreatedByUserFilter, getPullRequestGroups } from './lib/utils';
-import { useDashboardPullRequests, useUserEmail } from '../../hooks';
+import { PullRequestColumnConfig, PullRequestGroup } from './lib/types';
+import React, { useState } from 'react';
+import { getPullRequestGroupConfigs, getPullRequestGroups } from './lib/utils';
-import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { FilterType } from './lib/filters';
import { PullRequestGrid } from './lib/PullRequestGrid';
-
-function usePullRequestGroupConfigs(
- userEmail: string | undefined,
-): PullRequestGroupConfig[] {
- const [pullRequestGroupConfigs, setPullRequestGroupConfigs] = useState<
- PullRequestGroupConfig[]
- >([]);
-
- useEffect(() => {
- const prGroupConfigs: PullRequestGroupConfig[] = [
- { title: 'Created by me', filter: getCreatedByUserFilter(userEmail) },
- { title: 'Other PRs', filter: _ => true, simplified: false },
- ];
-
- setPullRequestGroupConfigs(prGroupConfigs);
- }, [userEmail]);
-
- return pullRequestGroupConfigs;
-}
-
-function usePullRequestGroups(
- pullRequests: DashboardPullRequest[] | undefined,
- pullRequestGroupConfigs: PullRequestGroupConfig[],
-): PullRequestGroup[] {
- const [pullRequestGroups, setPullRequestGroups] = useState<
- PullRequestGroup[]
- >([]);
-
- useEffect(() => {
- if (pullRequests) {
- const groups = getPullRequestGroups(
- pullRequests,
- pullRequestGroupConfigs,
- );
- setPullRequestGroups(groups);
- }
- }, [pullRequests, pullRequestGroupConfigs]);
-
- return pullRequestGroups;
-}
+import { useDashboardPullRequests } from '../../hooks';
+import { useFilterProcessor } from './lib/hooks';
type PullRequestsPageContentProps = {
- pullRequestGroups: PullRequestGroup[];
+ pullRequestGroups: PullRequestGroup[] | undefined;
loading: boolean;
error?: Error;
};
@@ -80,7 +41,7 @@ const PullRequestsPageContent = ({
loading,
error,
}: PullRequestsPageContentProps) => {
- if (loading && pullRequestGroups.length <= 0) {
+ if (loading && (!pullRequestGroups || pullRequestGroups.length <= 0)) {
return ;
}
@@ -88,25 +49,50 @@ const PullRequestsPageContent = ({
return ;
}
- return ;
+ return ;
};
+const DEFAULT_COLUMN_CONFIGS: PullRequestColumnConfig[] = [
+ {
+ title: 'Created by me',
+ filters: [{ type: FilterType.CreatedByCurrentUser }],
+ simplified: false,
+ },
+ {
+ title: 'Other PRs',
+ filters: [{ type: FilterType.All }],
+ simplified: true,
+ },
+];
+
type PullRequestsPageProps = {
projectName?: string;
pollingInterval?: number;
+ defaultColumnConfigs?: PullRequestColumnConfig[];
};
export const PullRequestsPage = ({
projectName,
pollingInterval,
+ defaultColumnConfigs,
}: PullRequestsPageProps) => {
const { pullRequests, loading, error } = useDashboardPullRequests(
projectName,
pollingInterval,
);
- const userEmail = useUserEmail();
- const pullRequestGroupConfigs = usePullRequestGroupConfigs(userEmail);
- const pullRequestGroups = usePullRequestGroups(
+
+ const [columnConfigs] = useState(
+ defaultColumnConfigs ?? DEFAULT_COLUMN_CONFIGS,
+ );
+
+ const filterProcessor = useFilterProcessor();
+
+ const pullRequestGroupConfigs = getPullRequestGroupConfigs(
+ columnConfigs,
+ filterProcessor,
+ );
+
+ const pullRequestGroups = getPullRequestGroups(
pullRequests,
pullRequestGroupConfigs,
);
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/index.ts
index e8b6cfa6bb..4061c72a8e 100644
--- a/plugins/azure-devops/src/components/PullRequestsPage/index.ts
+++ b/plugins/azure-devops/src/components/PullRequestsPage/index.ts
@@ -15,3 +15,17 @@
*/
export { PullRequestsPage } from './PullRequestsPage';
+export type { PullRequestColumnConfig } from './lib/types';
+export { FilterType } from './lib/filters';
+export type {
+ BaseFilter,
+ Filter,
+ PullRequestFilter,
+ AssignedToUserFilter,
+ CreatedByUserFilter,
+ AssignedToTeamFilter,
+ CreatedByTeamFilter,
+ AssignedToTeamsFilter,
+ CreatedByTeamsFilter,
+ AllFilter,
+} from './lib/filters';
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts
new file mode 100644
index 0000000000..90ec822ef6
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 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 { BaseFilter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+
+export type AllFilter = BaseFilter & {
+ type: FilterType.All;
+};
+
+export function createAllFilter(): PullRequestFilter {
+ return (_pullRequest: DashboardPullRequest): boolean => true;
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts
new file mode 100644
index 0000000000..8e816db2c3
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 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 { BaseFilter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { stringArrayHas } from '../../../../utils';
+
+export type AssignedToTeamFilter = BaseFilter & {
+ type: FilterType.AssignedToTeam;
+ teamId: string;
+};
+
+export function createAssignedToTeamFilter(
+ filter: AssignedToTeamFilter,
+): PullRequestFilter {
+ return (pullRequest: DashboardPullRequest): boolean => {
+ const reviewerIds = pullRequest.reviewers?.map(reviewer => reviewer.id);
+
+ if (!reviewerIds) {
+ return false;
+ }
+
+ return stringArrayHas(reviewerIds, filter.teamId, true);
+ };
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts
new file mode 100644
index 0000000000..ce5e5bcc11
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 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 { BaseFilter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { createAssignedToTeamFilter } from './assignedToTeamFilter';
+
+export type AssignedToTeamsFilter = BaseFilter &
+ (
+ | {
+ type: FilterType.AssignedToTeams;
+ teamIds: string[];
+ }
+ | {
+ type: FilterType.AssignedToCurrentUsersTeams;
+ teamIds?: string[];
+ }
+ );
+
+export function createAssignedToTeamsFilter(
+ filter: AssignedToTeamsFilter,
+): PullRequestFilter {
+ const teamIds = filter.teamIds;
+
+ return (pullRequest: DashboardPullRequest): boolean => {
+ if (!teamIds) {
+ return false;
+ }
+
+ return teamIds.some(teamId => {
+ return createAssignedToTeamFilter({
+ type: FilterType.AssignedToTeam,
+ teamId,
+ })(pullRequest);
+ });
+ };
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts
new file mode 100644
index 0000000000..95ee3d5a59
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 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 { BaseFilter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { stringArrayHas } from '../../../../utils';
+
+export type AssignedToUserFilter = BaseFilter &
+ (
+ | {
+ type: FilterType.AssignedToUser;
+ email: string;
+ }
+ | {
+ type: FilterType.AssignedToCurrentUser;
+ email?: string;
+ }
+ );
+
+export function createAssignedToUserFilter(
+ filter: AssignedToUserFilter,
+): PullRequestFilter {
+ const email = filter.email;
+
+ return (pullRequest: DashboardPullRequest): boolean => {
+ const uniqueNames = pullRequest.reviewers?.map(
+ reviewer => reviewer.uniqueName,
+ );
+
+ if (!email || !uniqueNames) {
+ return false;
+ }
+
+ return stringArrayHas(uniqueNames, email, true);
+ };
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.test.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.test.ts
new file mode 100644
index 0000000000..b0ac4d402b
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.test.ts
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2021 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 { Filter, FilterType } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { createFilter } from './createFilter';
+
+describe('createFilter', () => {
+ const pullRequest = {
+ createdBy: {
+ uniqueName: 'user1@backstage.com',
+ teamIds: ['team1Id', 'team2Id'],
+ },
+ reviewers: [
+ { uniqueName: 'user2@backstage.com' },
+ { id: 'team2Id' },
+ { id: 'team3Id' },
+ ],
+ } as DashboardPullRequest;
+
+ const testCases: Array<{ filter: Filter; result: boolean }> = [
+ {
+ filter: {
+ type: FilterType.AssignedToUser,
+ email: 'user2@backstage.com',
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.AssignedToUser,
+ email: 'random-user@backstage.com',
+ },
+ result: false,
+ },
+ {
+ filter: {
+ type: FilterType.CreatedByUser,
+ email: 'user1@backstage.com',
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.CreatedByUser,
+ email: 'random-user@backstage.com',
+ },
+ result: false,
+ },
+ {
+ filter: {
+ type: FilterType.AssignedToTeam,
+ teamId: 'team2Id',
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.AssignedToTeam,
+ teamId: 'randomTeamId',
+ },
+ result: false,
+ },
+ {
+ filter: {
+ type: FilterType.CreatedByTeam,
+ teamId: 'team1Id',
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.CreatedByTeam,
+ teamId: 'randomTeamId',
+ },
+ result: false,
+ },
+ {
+ filter: {
+ type: FilterType.AssignedToTeams,
+ teamIds: ['team2Id', 'randomTeamId'],
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.AssignedToTeams,
+ teamIds: ['team2Id', 'team3Id'],
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.AssignedToTeams,
+ teamIds: ['randomTeam1Id', 'randomTeam2Id'],
+ },
+ result: false,
+ },
+ {
+ filter: {
+ type: FilterType.CreatedByTeams,
+ teamIds: ['team1Id', 'randomTeamId'],
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.CreatedByTeams,
+ teamIds: ['team1Id', 'team2Id'],
+ },
+ result: true,
+ },
+ {
+ filter: {
+ type: FilterType.CreatedByTeams,
+ teamIds: ['randomTeam1Id', 'randomTeam2Id'],
+ },
+ result: false,
+ },
+ {
+ filter: {
+ type: FilterType.All,
+ },
+ result: true,
+ },
+ ];
+
+ testCases.forEach(({ filter, result }) => {
+ it(`should return ${String(result)} when pull request ${
+ result ? 'is' : 'is not'
+ } ${filter.type}`, () => {
+ const pullRequestFilter = createFilter(filter);
+ expect(pullRequestFilter(pullRequest)).toBe(result);
+ });
+ });
+});
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.ts
new file mode 100644
index 0000000000..492d0539c5
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.ts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2021 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 { Filter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { createAllFilter } from './allFilter';
+import { createAssignedToTeamFilter } from './assignedToTeamFilter';
+import { createAssignedToTeamsFilter } from './assignedToTeamsFilter';
+import { createAssignedToUserFilter } from './assignedToUserFilter';
+import { createCreatedByTeamFilter } from './createdByTeamFilter';
+import { createCreatedByTeamsFilter } from './createdByTeamsFilter';
+import { createCreatedByUserFilter } from './createdByUserFilter';
+
+export function createFilter(filters: Filter | Filter[]): PullRequestFilter {
+ const mapFilter = (filter: Filter): PullRequestFilter => {
+ switch (filter.type) {
+ case FilterType.AssignedToUser:
+ case FilterType.AssignedToCurrentUser:
+ return createAssignedToUserFilter(filter);
+
+ case FilterType.CreatedByUser:
+ case FilterType.CreatedByCurrentUser:
+ return createCreatedByUserFilter(filter);
+
+ case FilterType.AssignedToTeam:
+ return createAssignedToTeamFilter(filter);
+
+ case FilterType.CreatedByTeam:
+ return createCreatedByTeamFilter(filter);
+
+ case FilterType.AssignedToTeams:
+ case FilterType.AssignedToCurrentUsersTeams:
+ return createAssignedToTeamsFilter(filter);
+
+ case FilterType.CreatedByTeams:
+ case FilterType.CreatedByCurrentUsersTeams:
+ return createCreatedByTeamsFilter(filter);
+
+ case FilterType.All:
+ return createAllFilter();
+
+ default:
+ return _ => false;
+ }
+ };
+
+ if (Array.isArray(filters)) {
+ if (filters.length === 1) {
+ return mapFilter(filters[0]);
+ }
+
+ return (pullRequest: DashboardPullRequest): boolean =>
+ filters.every(filter => mapFilter(filter)(pullRequest));
+ }
+
+ return mapFilter(filters);
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts
new file mode 100644
index 0000000000..70a388b540
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 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 { BaseFilter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { stringArrayHas } from '../../../../utils';
+
+export type CreatedByTeamFilter = BaseFilter &
+ ({
+ type: FilterType.CreatedByTeam;
+ } & ({ teamId: string } | { teamName: string }));
+
+export function createCreatedByTeamFilter(
+ filter: CreatedByTeamFilter,
+): PullRequestFilter {
+ return (pullRequest: DashboardPullRequest): boolean => {
+ const [createdByTeams, team] =
+ 'teamId' in filter
+ ? [pullRequest.createdBy?.teamIds, filter.teamId]
+ : [pullRequest.createdBy?.teamNames, filter.teamName];
+
+ if (!createdByTeams) {
+ return false;
+ }
+
+ return stringArrayHas(createdByTeams, team, true);
+ };
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts
new file mode 100644
index 0000000000..34ed81db5d
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2021 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 { BaseFilter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { createCreatedByTeamFilter } from './createdByTeamFilter';
+
+export type CreatedByTeamsFilter = BaseFilter &
+ (
+ | ({
+ type: FilterType.CreatedByTeams;
+ } & ({ teamIds: string[] } | { teamNames: string[] }))
+ | {
+ type: FilterType.CreatedByCurrentUsersTeams;
+ teamIds?: string[];
+ }
+ );
+
+export function createCreatedByTeamsFilter(
+ filter: CreatedByTeamsFilter,
+): PullRequestFilter {
+ return (pullRequest: DashboardPullRequest): boolean => {
+ if ('teamNames' in filter) {
+ const teamNames = filter.teamNames;
+
+ if (!teamNames) {
+ return false;
+ }
+
+ return teamNames.some(teamName => {
+ return createCreatedByTeamFilter({
+ type: FilterType.CreatedByTeam,
+ teamName,
+ })(pullRequest);
+ });
+ }
+
+ const teamIds = filter.teamIds;
+
+ if (!teamIds) {
+ return false;
+ }
+
+ return teamIds.some(teamId => {
+ return createCreatedByTeamFilter({
+ type: FilterType.CreatedByTeam,
+ teamId,
+ })(pullRequest);
+ });
+ };
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts
new file mode 100644
index 0000000000..69d4f23db5
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021 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 { BaseFilter, FilterType, PullRequestFilter } from './types';
+
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+import { equalsIgnoreCase } from '../../../../utils';
+
+export type CreatedByUserFilter = BaseFilter &
+ (
+ | {
+ type: FilterType.CreatedByUser;
+ email: string;
+ }
+ | {
+ type: FilterType.CreatedByCurrentUser;
+ email?: string;
+ }
+ );
+
+export function createCreatedByUserFilter(
+ filter: CreatedByUserFilter,
+): PullRequestFilter {
+ const email = filter.email;
+
+ return (pullRequest: DashboardPullRequest): boolean => {
+ const uniqueName = pullRequest.createdBy?.uniqueName;
+
+ if (!email || !uniqueName) {
+ return false;
+ }
+
+ return equalsIgnoreCase(email, uniqueName);
+ };
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts
new file mode 100644
index 0000000000..df165dc9ca
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 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 { createFilter } from './createFilter';
+export { FilterTypes, FilterType } from './types';
+export type {
+ BaseFilter,
+ Filter,
+ PullRequestFilter,
+ AssignedToUserFilter,
+ CreatedByUserFilter,
+ AssignedToTeamFilter,
+ CreatedByTeamFilter,
+ AssignedToTeamsFilter,
+ CreatedByTeamsFilter,
+ AllFilter,
+} from './types';
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts
new file mode 100644
index 0000000000..bc4643d51b
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2021 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 { AllFilter } from './allFilter';
+import { AssignedToTeamFilter } from './assignedToTeamFilter';
+import { AssignedToTeamsFilter } from './assignedToTeamsFilter';
+import { AssignedToUserFilter } from './assignedToUserFilter';
+import { CreatedByTeamFilter } from './createdByTeamFilter';
+import { CreatedByTeamsFilter } from './createdByTeamsFilter';
+import { CreatedByUserFilter } from './createdByUserFilter';
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+
+export enum FilterType {
+ All = 'All',
+
+ // Assigned To
+ AssignedToUser = 'AssignedToUser',
+ AssignedToCurrentUser = 'AssignedToCurrentUser',
+ AssignedToTeam = 'AssignedToTeam',
+ AssignedToTeams = 'AssignedToTeams',
+ AssignedToCurrentUsersTeams = 'AssignedToCurrentUsersTeams',
+
+ // Created By
+ CreatedByUser = 'CreatedByUser',
+ CreatedByCurrentUser = 'CreatedByCurrentUser',
+ CreatedByTeam = 'CreatedByTeam',
+ CreatedByTeams = 'CreatedByTeams',
+ CreatedByCurrentUsersTeams = 'CreatedByCurrentUsersTeams',
+}
+
+export const FilterTypes = [
+ FilterType.All,
+
+ FilterType.AssignedToUser,
+ FilterType.AssignedToCurrentUser,
+ FilterType.AssignedToTeam,
+ FilterType.AssignedToTeams,
+ FilterType.AssignedToCurrentUsersTeams,
+
+ FilterType.CreatedByUser,
+ FilterType.CreatedByCurrentUser,
+ FilterType.CreatedByTeam,
+ FilterType.CreatedByTeams,
+ FilterType.CreatedByCurrentUsersTeams,
+] as const;
+
+export type BaseFilter = {
+ type: FilterType;
+};
+
+export type Filter =
+ | AssignedToUserFilter
+ | CreatedByUserFilter
+ | AssignedToTeamFilter
+ | CreatedByTeamFilter
+ | AssignedToTeamsFilter
+ | CreatedByTeamsFilter
+ | AllFilter;
+
+export type {
+ AssignedToUserFilter,
+ CreatedByUserFilter,
+ AssignedToTeamFilter,
+ CreatedByTeamFilter,
+ AssignedToTeamsFilter,
+ CreatedByTeamsFilter,
+ AllFilter,
+};
+
+export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean;
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/index.ts
new file mode 100644
index 0000000000..2e87dfea0c
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2021 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 './useFilterProcessor';
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts
new file mode 100644
index 0000000000..546b23430d
--- /dev/null
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 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 { Filter, FilterType } from '../filters';
+
+import { useUserEmail } from '../../../../hooks';
+
+export function useFilterProcessor(): (filters: Filter[]) => Filter[] {
+ const userEmail = useUserEmail();
+
+ return (filters: Filter[]): Filter[] => {
+ for (const filter of filters) {
+ switch (filter.type) {
+ case FilterType.AssignedToCurrentUser:
+ case FilterType.CreatedByCurrentUser:
+ filter.email = userEmail;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return filters;
+ };
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts
index 2d936f7b64..74c8ebe605 100644
--- a/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts
@@ -14,23 +14,24 @@
* limitations under the License.
*/
-import {
- DashboardPullRequest,
- Team,
-} from '@backstage/plugin-azure-devops-common';
+import { Filter, PullRequestFilter } from './filters';
-export interface PullRequestGroup {
+import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
+
+export interface PullRequestColumnConfig {
title: string;
- pullRequests: DashboardPullRequest[];
+ filters: Filter[];
simplified?: boolean;
}
-export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean;
-
-export type TeamFilter = (team: Team) => boolean;
-
export interface PullRequestGroupConfig {
title: string;
filter: PullRequestFilter;
simplified?: boolean;
}
+
+export interface PullRequestGroup {
+ title: string;
+ pullRequests: DashboardPullRequest[];
+ simplified?: boolean;
+}
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts
index da27b2e06e..d128cbd1db 100644
--- a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts
@@ -19,33 +19,7 @@ import {
PullRequestVoteStatus,
Reviewer,
} from '@backstage/plugin-azure-devops-common';
-import {
- arrayExtract,
- getCreatedByUserFilter,
- getPullRequestGroups,
- reviewerFilter,
-} from './utils';
-
-describe('getCreatedByUserFilter', () => {
- it('should filter if pull request is created by user', () => {
- const userEmail = 'user1@backstage.com';
- const pr = {
- createdBy: { uniqueName: userEmail },
- } as DashboardPullRequest;
- const result = getCreatedByUserFilter(userEmail)(pr);
- expect(result).toBe(true);
- });
-
- it('should not filter if pull request is not created by user', () => {
- const userEmail1 = 'user1@backstage.com';
- const userEmail2 = 'user2@backstage.com';
- const pr = {
- createdBy: { uniqueName: userEmail1 },
- } as DashboardPullRequest;
- const result = getCreatedByUserFilter(userEmail2)(pr);
- expect(result).toBe(false);
- });
-});
+import { arrayExtract, getPullRequestGroups, reviewerFilter } from './utils';
describe('reviewerFilter', () => {
it('should return false if reviewer has no vote and is not required', () => {
@@ -128,11 +102,15 @@ describe('getPullRequestGroups', () => {
];
const configs = [
- { title: 'Created by me', filter: getCreatedByUserFilter(userEmail) },
+ {
+ title: 'Created by me',
+ filter: (pullRequest: DashboardPullRequest): boolean =>
+ pullRequest.createdBy?.uniqueName === userEmail,
+ },
{ title: 'Other PRs', filter: (_: unknown) => true, simplified: true },
];
- const result = getPullRequestGroups(pullRequests, configs);
+ const result = getPullRequestGroups(pullRequests, configs) ?? [];
expect(result.length).toBe(2);
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts
index c9cf866010..c4fcdc9f7e 100644
--- a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts
@@ -19,25 +19,13 @@ import {
PullRequestVoteStatus,
Reviewer,
} from '@backstage/plugin-azure-devops-common';
+import { Filter, createFilter } from './filters';
import {
- PullRequestFilter,
+ PullRequestColumnConfig,
PullRequestGroup,
PullRequestGroupConfig,
} from './types';
-/**
- * Creates a filter that matches pull requests created by `userEmail`.
- * @param userEmail an email to filter by.
- * @returns a filter for pull requests created by `userEmail`.
- */
-export function getCreatedByUserFilter(
- userEmail: string | undefined,
-): PullRequestFilter {
- return (pullRequest: DashboardPullRequest): boolean =>
- pullRequest.createdBy?.uniqueName?.toLocaleLowerCase() ===
- userEmail?.toLocaleLowerCase();
-}
-
/**
* Filters a reviewer based on vote status and if the reviewer is required.
* @param reviewer a reviewer to filter.
@@ -97,9 +85,13 @@ export function arrayExtract(arr: T[], filter: (value: T) => unknown): T[] {
* @returns a list of pull request groups.
*/
export function getPullRequestGroups(
- pullRequests: DashboardPullRequest[],
+ pullRequests: DashboardPullRequest[] | undefined,
configs: PullRequestGroupConfig[],
-): PullRequestGroup[] {
+): PullRequestGroup[] | undefined {
+ if (!pullRequests) {
+ return undefined;
+ }
+
const remainingPullRequests: DashboardPullRequest[] = [...pullRequests];
const pullRequestGroups: PullRequestGroup[] = [];
@@ -115,3 +107,17 @@ export function getPullRequestGroups(
return pullRequestGroups;
}
+
+export function getPullRequestGroupConfigs(
+ columnConfigs: PullRequestColumnConfig[],
+ filterProcessor: (filters: Filter[]) => Filter[],
+): PullRequestGroupConfig[] {
+ return columnConfigs.map(columnConfig => {
+ const filters = filterProcessor(columnConfig.filters);
+ return {
+ title: columnConfig.title,
+ filter: createFilter(filters),
+ simplified: columnConfig.simplified,
+ };
+ });
+}
diff --git a/plugins/azure-devops/src/index.ts b/plugins/azure-devops/src/index.ts
index c9b804bc8d..8289a93a5c 100644
--- a/plugins/azure-devops/src/index.ts
+++ b/plugins/azure-devops/src/index.ts
@@ -23,3 +23,18 @@ export {
} from './plugin';
export { AzurePullRequestsIcon } from './components/AzurePullRequestsIcon';
+
+export { FilterType } from './components/PullRequestsPage';
+export type {
+ PullRequestColumnConfig,
+ BaseFilter,
+ Filter,
+ PullRequestFilter,
+ AssignedToUserFilter,
+ CreatedByUserFilter,
+ AssignedToTeamFilter,
+ CreatedByTeamFilter,
+ AssignedToTeamsFilter,
+ CreatedByTeamsFilter,
+ AllFilter,
+} from './components/PullRequestsPage';
diff --git a/plugins/azure-devops/src/utils/arrayHas.ts b/plugins/azure-devops/src/utils/arrayHas.ts
new file mode 100644
index 0000000000..8dac8b8ec9
--- /dev/null
+++ b/plugins/azure-devops/src/utils/arrayHas.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 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 function arrayHas(arr: T[], value: T): boolean {
+ return new Set(arr).has(value);
+}
+
+export function stringArrayHas(
+ arr: Array,
+ value: string | undefined,
+ ignoreCase: boolean = false,
+): boolean {
+ if (ignoreCase) {
+ return arrayHas(
+ arr.map(a => a?.toLocaleLowerCase('en-US')),
+ value?.toLocaleLowerCase('en-US'),
+ );
+ }
+
+ return arrayHas(arr, value);
+}
diff --git a/plugins/azure-devops/src/utils/equalsIgnoreCase.ts b/plugins/azure-devops/src/utils/equalsIgnoreCase.ts
new file mode 100644
index 0000000000..12b058e6ae
--- /dev/null
+++ b/plugins/azure-devops/src/utils/equalsIgnoreCase.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 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 function equalsIgnoreCase(str1: string, str2: string): boolean {
+ return str1.toLocaleLowerCase('en-US') === str2.toLocaleLowerCase('en-US');
+}
diff --git a/plugins/azure-devops/src/utils/index.ts b/plugins/azure-devops/src/utils/index.ts
new file mode 100644
index 0000000000..f2214e8106
--- /dev/null
+++ b/plugins/azure-devops/src/utils/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 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 './arrayHas';
+export * from './equalsIgnoreCase';
+export * from './getDurationFromDates';