refactored: Improved types and small code improvements.

Signed-off-by: Marley Powell <Marley.Powell@exclaimer.com>
This commit is contained in:
Marley Powell
2021-11-10 14:53:40 +00:00
parent 1bd69aa3f3
commit 96c562bb22
8 changed files with 247 additions and 57 deletions
+125
View File
@@ -126,3 +126,128 @@ export type PullRequestOptions = {
top: number;
status: PullRequestStatus;
};
export interface DashboardPullRequest {
pullRequestId: number | undefined;
title: string | undefined;
description: string | undefined;
repository: Repository | undefined;
createdBy: CreatedBy | undefined;
hasAutoComplete: boolean;
policies: Policy[] | undefined;
reviewers: Reviewer[] | undefined;
creationDate: string | undefined;
status: PullRequestStatus | undefined;
isDraft: boolean | undefined;
link: string | undefined;
}
export interface Reviewer {
id: string | undefined;
displayName: string | undefined;
imageUrl: string | undefined;
isRequired: boolean | undefined;
isContainer: boolean | undefined;
voteStatus: PullRequestVoteStatus;
}
export interface Policy {
id: number | undefined;
type: PolicyType;
status: PolicyEvaluationStatus | undefined;
text: string | undefined;
link: string | undefined;
}
export interface CreatedBy {
id: string | undefined;
displayName: string | undefined;
uniqueName: string | undefined;
imageUrl: string | undefined;
}
export interface Repository {
id: string | undefined;
name: string | undefined;
url: string | undefined;
}
export interface Team {
id: string | undefined;
name: string | undefined;
memberIds: string[] | undefined;
}
/**
* Status of a policy which is running against a specific pull request.
*/
export enum PolicyEvaluationStatus {
/**
* The policy is either queued to run, or is waiting for some event before progressing.
*/
Queued = 0,
/**
* The policy is currently running.
*/
Running = 1,
/**
* The policy has been fulfilled for this pull request.
*/
Approved = 2,
/**
* The policy has rejected this pull request.
*/
Rejected = 3,
/**
* The policy does not apply to this pull request.
*/
NotApplicable = 4,
/**
* The policy has encountered an unexpected error.
*/
Broken = 5,
}
export enum PolicyType {
Build = 'Build',
Status = 'Status',
MinimumReviewers = 'MinimumReviewers',
Comments = 'Comments',
RequiredReviewers = 'RequiredReviewers',
MergeStrategy = 'MergeStrategy',
}
export const PolicyTypeId = {
/**
* This policy will require a successful build has been performed before updating protected refs.
*/
Build: '0609b952-1397-4640-95ec-e00a01b2c241',
/**
* This policy will require a successful status to be posted before updating protected refs.
*/
Status: 'cbdc66da-9728-4af8-aada-9a5a32e4a226',
/**
* This policy will ensure that a minimum number of reviewers have approved a pull request before completion.
*/
MinimumReviewers: 'fa4e907d-c16b-4a4c-9dfa-4906e5d171dd',
/**
* Check if the pull request has any active comments.
*/
Comments: 'c6a1889d-b943-4856-b76f-9e46bb6b0df2',
/**
* This policy will ensure that required reviewers are added for modified files matching specified patterns.
*/
RequiredReviewers: 'fd2167ab-b0be-447a-8ec8-39368250530e',
/**
* This policy ensures that pull requests use a consistent merge strategy.
*/
MergeStrategy: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
};
export enum PullRequestVoteStatus {
Approved = 10,
ApprovedWithSuggestions = 5,
NoVote = 0,
WaitingForAuthor = -5,
Rejected = -10,
}
@@ -14,10 +14,16 @@
* limitations under the License.
*/
import {
DashboardPullRequest,
PolicyEvaluationStatus,
PolicyType,
PullRequestStatus,
PullRequestVoteStatus,
} from '@backstage/plugin-azure-devops-common';
import { MemoryRouter } from 'react-router';
import { PullRequest } from '../../../../api/types';
import { PullRequestCard } from './PullRequestCard';
import { PullRequestStatus } from 'azure-devops-node-api/interfaces/GitInterfaces';
import React from 'react';
export default {
@@ -25,16 +31,17 @@ export default {
component: PullRequestCard,
};
const pullRequest: PullRequest = {
const pullRequest: DashboardPullRequest = {
pullRequestId: 1,
title:
"feat(EXUX-4091): 🛂 Added the admin role authorization to the backend API's",
description:
'This PR contains the following updates:\n\n| Package | Type | Update | Change |\n|---|---|---|---|\n| [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint) | devDependencies | major | [`4.33.0` -> `5.0.0`](https://renovatebot.com/diffs/npm/@typescript-eslint%2feslint-plugin/4.33.0/5.0.0) |\n| [@typescript-eslint/parser](https://github.com/typescript-eslint/typescrip',
link: '',
link: undefined,
repository: {
id: undefined,
name: 'backstage',
url: '',
url: undefined,
},
createdBy: {
id: '',
@@ -44,31 +51,56 @@ const pullRequest: PullRequest = {
'https://dev.azure.com/exclaimerltd/_api/_common/identityImage?id=e6c0634b-68d2-6e6f-aa7d-adccada23216',
},
reviewers: [
{ displayName: 'Marley', imageUrl: '' },
{ displayName: 'User 1', imageUrl: '' },
{ displayName: 'User 2', imageUrl: '' },
{
id: undefined,
displayName: 'Marley',
imageUrl: '',
isRequired: true,
isContainer: false,
voteStatus: PullRequestVoteStatus.Approved,
},
{
id: undefined,
displayName: 'User 1',
imageUrl: '',
isRequired: false,
isContainer: false,
voteStatus: PullRequestVoteStatus.WaitingForAuthor,
},
{
id: undefined,
displayName: 'User 2',
imageUrl: '',
isRequired: true,
isContainer: false,
voteStatus: PullRequestVoteStatus.NoVote,
},
],
policies: [
{
type: 'Build',
status: 'Running',
id: undefined,
type: PolicyType.Build,
status: PolicyEvaluationStatus.Running,
text: 'Build: UI (running)',
link: undefined,
},
{
type: 'MinimumReviewers',
id: undefined,
type: PolicyType.MinimumReviewers,
text: 'Minimum number of reviewers (2)',
status: '',
status: undefined,
link: undefined,
},
{
type: 'Comments',
id: undefined,
type: PolicyType.Comments,
text: 'Comment requirements',
status: '',
status: undefined,
link: undefined,
},
],
hasAutoComplete: true,
creationDate: new Date(Date.now() - 10000000).toISOString(),
sourceRefName: '',
targetRefName: '',
status: PullRequestStatus.Active,
isDraft: false,
};
@@ -18,8 +18,8 @@ import { Card, CardContent, CardHeader, Link } from '@material-ui/core';
import { AutoCompleteIcon } from '../AutoCompleteIcon';
import { Avatar } from '@backstage/core-components';
import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common';
import { DateTime } from 'luxon';
import { PullRequest } from '../../../../api/types';
import { PullRequestCardPolicies } from './PullRequestCardPolicies';
import { PullRequestCardReviewers } from './PullRequestCardReviewers';
import React from 'react';
@@ -53,7 +53,7 @@ const useStyles = makeStyles(
);
type PullRequestCardProps = {
pullRequest: PullRequest;
pullRequest: DashboardPullRequest;
simplified?: boolean;
};
@@ -75,21 +75,23 @@ export const PullRequestCard = ({
const subheader = (
<span>
<Link
href={pullRequest.repository.url}
href={pullRequest.repository?.url}
color="inherit"
target="_blank"
rel="noopener noreferrer"
>
{pullRequest.repository.name}
{pullRequest.repository?.name}
</Link>{' '}
· {DateTime.fromISO(pullRequest.creationDate.toString()).toRelative()}
·{' '}
{pullRequest.creationDate &&
DateTime.fromISO(pullRequest.creationDate).toRelative()}
</span>
);
const avatar = (
<Avatar
displayName={pullRequest.createdBy.displayName}
picture={pullRequest.createdBy.imageUrl}
displayName={pullRequest.createdBy?.displayName}
picture={pullRequest.createdBy?.imageUrl}
customStyles={{ width: '2.5rem', height: '2.5rem', fontSize: '1rem' }}
/>
);
@@ -97,7 +99,10 @@ export const PullRequestCard = ({
const classes = useStyles();
return (
<Card classes={{ root: classes.card }}>
<Card
classes={{ root: classes.card }}
data-pull-request-id={pullRequest.pullRequestId}
>
<CardHeader
avatar={avatar}
title={title}
@@ -113,12 +118,16 @@ export const PullRequestCard = ({
{!simplified && (
<CardContent className={classes.content}>
<PullRequestCardPolicies
policies={pullRequest.policies}
className={classes.policies}
/>
{pullRequest.policies && (
<PullRequestCardPolicies
policies={pullRequest.policies}
className={classes.policies}
/>
)}
<PullRequestCardReviewers reviewers={pullRequest.reviewers} />
{pullRequest.reviewers && (
<PullRequestCardReviewers reviewers={pullRequest.reviewers} />
)}
</CardContent>
)}
</Card>
@@ -14,6 +14,11 @@
* limitations under the License.
*/
import {
Policy,
PolicyEvaluationStatus,
PolicyType,
} from '@backstage/plugin-azure-devops-common';
import {
PolicyInProgressIcon,
PolicyIssueIcon,
@@ -21,25 +26,24 @@ import {
PullRequestCardPolicy,
} from './PullRequestCardPolicy';
import { Policy } from '../../../../api/types';
import React from 'react';
function getPullRequestCardPolicy(policy: Policy): JSX.Element | null {
switch (policy.type) {
case 'Build':
case PolicyType.Build:
switch (policy.status) {
case 'Running':
case PolicyEvaluationStatus.Running:
return (
<PullRequestCardPolicy
policy={policy}
icon={<PolicyInProgressIcon />}
/>
);
case 'Rejected':
case PolicyEvaluationStatus.Rejected:
return (
<PullRequestCardPolicy policy={policy} icon={<PolicyIssueIcon />} />
);
case 'Queued':
case PolicyEvaluationStatus.Queued:
return (
<PullRequestCardPolicy
policy={policy}
@@ -49,12 +53,12 @@ function getPullRequestCardPolicy(policy: Policy): JSX.Element | null {
default:
return null;
}
case 'MinimumReviewers':
case PolicyType.MinimumReviewers:
return (
<PullRequestCardPolicy policy={policy} icon={<PolicyRequiredIcon />} />
);
case 'Status':
case 'Comments':
case PolicyType.Status:
case PolicyType.Comments:
return (
<PullRequestCardPolicy policy={policy} icon={<PolicyIssueIcon />} />
);
@@ -18,7 +18,7 @@ import { styled, withStyles } from '@material-ui/core/styles';
import CancelIcon from '@material-ui/icons/Cancel';
import GroupWorkIcon from '@material-ui/icons/GroupWork';
import { Policy } from '../../../../api/types';
import { Policy } from '@backstage/plugin-azure-devops-common';
import React from 'react';
import WatchLaterIcon from '@material-ui/icons/WatchLater';
@@ -57,7 +57,7 @@ const PullRequestCardPolicyContainer = styled('div')({
type PullRequestCardPolicyProps = {
policy: Policy;
icon: React.ReactNode;
icon: JSX.Element;
};
export const PullRequestCardPolicy = ({
@@ -16,8 +16,7 @@
import { Avatar } from '@backstage/core-components';
import React from 'react';
import { Reviewer } from '../../../../api/types';
import { Tooltip } from '@material-ui/core';
import { Reviewer } from '@backstage/plugin-azure-devops-common';
type PullRequestCardReviewerProps = {
reviewer: Reviewer;
@@ -26,16 +25,14 @@ type PullRequestCardReviewerProps = {
export const PullRequestCardReviewer = ({
reviewer,
}: PullRequestCardReviewerProps) => (
<Tooltip title={reviewer.displayName}>
<Avatar
displayName={reviewer.displayName}
picture={reviewer.imageUrl}
customStyles={{
width: '2.5rem',
height: '2.5rem',
fontSize: '1rem',
border: '0.3rem solid silver',
}}
/>
</Tooltip>
<Avatar
displayName={reviewer.displayName}
picture={reviewer.imageUrl}
customStyles={{
width: '2.5rem',
height: '2.5rem',
fontSize: '1rem',
border: '0.3rem solid silver',
}}
/>
);
@@ -14,9 +14,13 @@
* limitations under the License.
*/
import {
PullRequestVoteStatus,
Reviewer,
} from '@backstage/plugin-azure-devops-common';
import { PullRequestCardReviewer } from './PullRequestCardReviewer';
import React from 'react';
import { Reviewer } from '../../../../api/types';
import { styled } from '@material-ui/core/styles';
const PullRequestCardReviewersContainer = styled('div')({
@@ -34,8 +38,14 @@ export const PullRequestCardReviewers = ({
reviewers,
}: PullRequestCardReviewersProps) => (
<PullRequestCardReviewersContainer>
{reviewers.map(reviewer => (
{reviewers.filter(reviewerFilter).map(reviewer => (
<PullRequestCardReviewer reviewer={reviewer} />
))}
</PullRequestCardReviewersContainer>
);
function reviewerFilter(reviewer: Reviewer): boolean {
return reviewer.voteStatus === PullRequestVoteStatus.NoVote
? !!reviewer.isRequired
: !reviewer.isContainer;
}
@@ -14,10 +14,23 @@
* limitations under the License.
*/
import { PullRequest } from '../../../api/types';
import {
DashboardPullRequest,
Team,
} from '@backstage/plugin-azure-devops-common';
export interface PullRequestGroup {
title: string;
pullRequests: PullRequest[];
pullRequests: DashboardPullRequest[];
simplified?: boolean;
}
export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean;
export type TeamFilter = (team: Team) => boolean;
export interface PullRequestGroupConfig {
title: string;
filter: PullRequestFilter;
simplified?: boolean;
}