mirror of
https://github.com/desktop/desktop
synced 2024-09-19 08:02:22 +00:00
First steps towards a pull request review dialog
This commit is contained in:
parent
e6a5089169
commit
d24923a5f6
|
@ -495,8 +495,10 @@ export interface IAPIPullRequest {
|
|||
|
||||
/** Information about a pull request review as returned by the GitHub API. */
|
||||
export interface IAPIPullRequestReview {
|
||||
readonly id: number
|
||||
readonly user: IAPIIdentity
|
||||
readonly body: string
|
||||
readonly html_url: string
|
||||
readonly state:
|
||||
| 'APPROVED'
|
||||
| 'DISMISSED'
|
||||
|
|
|
@ -20,6 +20,7 @@ import { ICommitMessage } from './commit-message'
|
|||
import { IAuthor } from './author'
|
||||
import { IRefCheck } from '../lib/ci-checks/ci-checks'
|
||||
import { GitHubRepository } from './github-repository'
|
||||
import { IAPIPullRequestReview } from '../lib/api'
|
||||
|
||||
export enum PopupType {
|
||||
RenameBranch = 1,
|
||||
|
@ -81,6 +82,7 @@ export enum PopupType {
|
|||
CICheckRunRerun,
|
||||
WarnForcePush,
|
||||
DiscardChangesRetry,
|
||||
PullRequestReview,
|
||||
}
|
||||
|
||||
export type Popup =
|
||||
|
@ -335,3 +337,10 @@ export type Popup =
|
|||
type: PopupType.DiscardChangesRetry
|
||||
retryAction: RetryAction
|
||||
}
|
||||
| {
|
||||
type: PopupType.PullRequestReview
|
||||
repository: RepositoryWithGitHubRepository
|
||||
pullRequest: PullRequest
|
||||
review: IAPIPullRequestReview
|
||||
needsSelectRepository: boolean
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ import * as ipcRenderer from '../lib/ipc-renderer'
|
|||
import { showNotification } from '../lib/stores/helpers/show-notification'
|
||||
import { DiscardChangesRetryDialog } from './discard-changes/discard-changes-retry-dialog'
|
||||
import { getReleaseSummary } from '../lib/release-notes'
|
||||
import { PullRequestReview } from './notifications/pull-request-review'
|
||||
|
||||
const MinuteInMilliseconds = 1000 * 60
|
||||
const HourInMilliseconds = MinuteInMilliseconds * 60
|
||||
|
@ -2027,7 +2028,7 @@ export class App extends React.Component<IAppProps, IAppState> {
|
|||
<PullRequestChecksFailed
|
||||
key="pull-request-checks-failed"
|
||||
dispatcher={this.props.dispatcher}
|
||||
shouldChangeRepository={popup.needsSelectRepository}
|
||||
shouldChangeRepository={popup.shouldChangeRepository}
|
||||
repository={popup.repository}
|
||||
pullRequest={popup.pullRequest}
|
||||
commitMessage={popup.commitMessage}
|
||||
|
@ -2080,6 +2081,22 @@ export class App extends React.Component<IAppProps, IAppState> {
|
|||
/>
|
||||
)
|
||||
}
|
||||
case PopupType.PullRequestReview: {
|
||||
return (
|
||||
<PullRequestReview
|
||||
key="pull-request-checks-failed"
|
||||
dispatcher={this.props.dispatcher}
|
||||
shouldChangeRepository={popup.shouldChangeRepository}
|
||||
repository={popup.repository}
|
||||
pullRequest={popup.pullRequest}
|
||||
review={popup.review}
|
||||
emoji={this.state.emoji}
|
||||
accounts={this.state.accounts}
|
||||
onSubmit={onPopupDismissedFn}
|
||||
onDismissed={onPopupDismissedFn}
|
||||
/>
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertNever(popup, `Unknown popup type: ${popup}`)
|
||||
}
|
||||
|
|
154
app/src/ui/notifications/pull-request-review.tsx
Normal file
154
app/src/ui/notifications/pull-request-review.tsx
Normal file
|
@ -0,0 +1,154 @@
|
|||
import * as React from 'react'
|
||||
import { Dialog, DialogContent, DialogFooter } from '../dialog'
|
||||
import { Row } from '../lib/row'
|
||||
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
|
||||
import { PullRequest } from '../../models/pull-request'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { Account } from '../../models/account'
|
||||
import { IAPIPullRequestReview } from '../../lib/api'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { RepositoryWithGitHubRepository } from '../../models/repository'
|
||||
import { SandboxedMarkdown } from '../lib/sandboxed-markdown'
|
||||
|
||||
interface IPullRequestReviewProps {
|
||||
readonly dispatcher: Dispatcher
|
||||
readonly shouldChangeRepository: boolean
|
||||
readonly accounts: ReadonlyArray<Account>
|
||||
readonly repository: RepositoryWithGitHubRepository
|
||||
readonly pullRequest: PullRequest
|
||||
readonly review: IAPIPullRequestReview
|
||||
/** Map from the emoji shortcut (e.g., :+1:) to the image's local path. */
|
||||
readonly emoji: Map<string, string>
|
||||
readonly onSubmit: () => void
|
||||
readonly onDismissed: () => void
|
||||
}
|
||||
|
||||
interface IPullRequestReviewState {
|
||||
readonly switchingToPullRequest: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog to show the result of a CI check run.
|
||||
*/
|
||||
export class PullRequestReview extends React.Component<
|
||||
IPullRequestReviewProps,
|
||||
IPullRequestReviewState
|
||||
> {
|
||||
public constructor(props: IPullRequestReviewProps) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
switchingToPullRequest: false,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
let okButtonTitle = __DARWIN__
|
||||
? 'Switch to Pull Request'
|
||||
: 'Switch to pull request'
|
||||
|
||||
if (this.props.shouldChangeRepository) {
|
||||
okButtonTitle = __DARWIN__
|
||||
? 'Switch to Repository and Pull Request'
|
||||
: 'Switch to repository and pull request'
|
||||
}
|
||||
|
||||
const { title, pullRequestNumber, base } = this.props.pullRequest
|
||||
|
||||
const header = (
|
||||
<div className="ci-check-run-dialog-header">
|
||||
<Octicon symbol={OcticonSymbol.xCircleFill} />
|
||||
<div className="title-container">
|
||||
<div className="summary">
|
||||
@{this.props.review.user.login} requested changes on your pull
|
||||
request
|
||||
</div>
|
||||
<span className="pr-title">
|
||||
<span className="pr-title">{title}</span>{' '}
|
||||
<span className="pr-number">#{pullRequestNumber}</span>{' '}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
id="pull-request-checks-failed"
|
||||
type="normal"
|
||||
title={header}
|
||||
dismissable={false}
|
||||
onSubmit={this.props.onSubmit}
|
||||
onDismissed={this.props.onDismissed}
|
||||
loading={this.state.switchingToPullRequest}
|
||||
>
|
||||
<DialogContent>
|
||||
<Row>
|
||||
<SandboxedMarkdown
|
||||
markdown={this.props.review.body}
|
||||
emoji={this.props.emoji}
|
||||
baseHref={base.gitHubRepository.htmlURL}
|
||||
repository={base.gitHubRepository}
|
||||
onMarkdownLinkClicked={this.onMarkdownLinkClicked}
|
||||
/>
|
||||
</Row>
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<Row>
|
||||
{this.renderSummary()}
|
||||
<OkCancelButtonGroup
|
||||
onCancelButtonClick={this.props.onDismissed}
|
||||
cancelButtonText="Dismiss"
|
||||
okButtonText={okButtonTitle}
|
||||
okButtonDisabled={this.state.switchingToPullRequest}
|
||||
onOkButtonClick={this.onSubmit}
|
||||
/>
|
||||
</Row>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
private onMarkdownLinkClicked = (url: string) => {
|
||||
this.props.dispatcher.openInBrowser(url)
|
||||
}
|
||||
|
||||
private renderSummary() {
|
||||
return (
|
||||
<div className="footer-question">
|
||||
<span>
|
||||
Do you want to switch to that Pull Request now and start working on
|
||||
the requested changes?
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// private onViewOnGitHub = (checkRun: IRefCheck) => {
|
||||
// const { repository, pullRequest, dispatcher, review } = this.props
|
||||
|
||||
// // Some checks do not provide htmlURLS like ones for the legacy status
|
||||
// // object as they do not have a view in the checks screen. In that case we
|
||||
// // will just open the PR and they can navigate from there... a little
|
||||
// // dissatisfying tho more of an edgecase anyways.
|
||||
// const url =
|
||||
// review.html_url ||
|
||||
// `${repository.gitHubRepository.htmlURL}/pull/${pullRequest.pullRequestNumber}#pullrequestreview-${review.id}`
|
||||
// if (url === null) {
|
||||
// // The repository should have a htmlURL.
|
||||
// return
|
||||
// }
|
||||
// dispatcher.openInBrowser(url)
|
||||
// }
|
||||
|
||||
private onSubmit = async (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault()
|
||||
const { dispatcher, repository, pullRequest } = this.props
|
||||
|
||||
this.setState({ switchingToPullRequest: true })
|
||||
await dispatcher.selectRepository(repository)
|
||||
await dispatcher.checkoutPullRequest(repository, pullRequest)
|
||||
this.setState({ switchingToPullRequest: false })
|
||||
|
||||
this.props.onDismissed()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue