diff --git a/app/src/lib/api.ts b/app/src/lib/api.ts index 9876bc0e80..99d89ac121 100644 --- a/app/src/lib/api.ts +++ b/app/src/lib/api.ts @@ -341,6 +341,7 @@ export interface IAPIRefCheckRun { readonly app: IAPIRefCheckRunApp readonly completed_at: string readonly started_at: string + readonly html_url: string } // NB. Only partially mapped diff --git a/app/src/lib/stores/commit-status-store.ts b/app/src/lib/stores/commit-status-store.ts index b6b6071ebc..a606da8f0f 100644 --- a/app/src/lib/stores/commit-status-store.ts +++ b/app/src/lib/stores/commit-status-store.ts @@ -36,6 +36,7 @@ export interface IRefCheck { readonly appName: string readonly checkSuiteId: number | null // API status don't have check suite id's readonly output: IRefCheckOutput + readonly htmlUrl: string | null } /** @@ -484,6 +485,7 @@ export class CommitStatusStore { mappedCheckRuns.push({ ...cr, + htmlUrl: matchingJob.html_url, output: { type: RefCheckOutputType.Actions, title: name, @@ -596,6 +598,7 @@ function apiStatusToRefCheck(apiStatus: IAPIRefStatusItem): IRefCheck { title: apiStatus.context, text: '', }, + htmlUrl: null, } } @@ -706,6 +709,7 @@ function apiCheckRunToRefCheck(checkRun: IAPIRefCheckRun): IRefCheck { summary: checkRun.output.summary, text: checkRun.output.text, }, + htmlUrl: checkRun.html_url, } } diff --git a/app/src/ui/branches/ci-check-list-item.tsx b/app/src/ui/branches/ci-check-list-item.tsx index e0be920113..a42923d7a7 100644 --- a/app/src/ui/branches/ci-check-list-item.tsx +++ b/app/src/ui/branches/ci-check-list-item.tsx @@ -10,6 +10,7 @@ import { Octicon } from '../octicons' import { getClassNameForCheck, getSymbolForCheck } from './ci-status' import classNames from 'classnames' import { APICheckConclusion } from '../../lib/api' +import { Button } from '../lib/button' interface ICICheckRunListItemProps { /** The check run to display **/ @@ -23,16 +24,23 @@ interface ICICheckRunListItemProps { /** Callback for when a check run is clicked */ readonly onCheckRunClick: (checkRun: IRefCheck) => void + + /** Callback to opens check runs on GitHub */ + readonly onViewOnGitHub: (checkRun: IRefCheck) => void } /** The CI check list item. */ export class CICheckRunListItem extends React.PureComponent< ICICheckRunListItemProps > { - public onCheckRunClick = () => { + private onCheckRunClick = () => { this.props.onCheckRunClick(this.props.checkRun) } + private onViewOnGitHub = () => { + this.props.onViewOnGitHub(this.props.checkRun) + } + private renderActionsLogOutput = (output: IRefCheckOutput) => { if (output.type === RefCheckOutputType.Default) { return null @@ -108,6 +116,14 @@ export class CICheckRunListItem extends React.PureComponent< ) } + private renderViewOnGitHub = () => { + return ( +
+ +
+ ) + } + private renderLogs = () => { const { loadingLogs, @@ -124,8 +140,11 @@ export class CICheckRunListItem extends React.PureComponent< return (
- {this.renderActionsLogOutput(output)} - {this.renderNonActionsLogOutput(output)} +
+ {this.renderActionsLogOutput(output)} + {this.renderNonActionsLogOutput(output)} +
+ {this.renderViewOnGitHub()}
) } diff --git a/app/src/ui/branches/ci-check-run-list.tsx b/app/src/ui/branches/ci-check-run-list.tsx index b327d85c3a..9e3e395af0 100644 --- a/app/src/ui/branches/ci-check-run-list.tsx +++ b/app/src/ui/branches/ci-check-run-list.tsx @@ -11,7 +11,6 @@ import _ from 'lodash' import { Button } from '../lib/button' import { CICheckRunListItem } from './ci-check-list-item' import * as OcticonSymbol from '../octicons/octicons.generated' - interface ICICheckRunListProps { /** The classname for the underlying element. */ readonly className?: string @@ -120,6 +119,21 @@ export class CICheckRunList extends React.PureComponent< this.setState({ checkRuns, loadingLogs: false }) } + private viewCheckRunsOnGitHub = (checkRun: IRefCheck): void => { + // 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 = + checkRun.htmlUrl ?? + `${this.props.repository.htmlURL}/pull/${this.props.prNumber}` + if (url === null) { + // The repository should have a htmlURL. + return + } + this.props.dispatcher.openInBrowser(url) + } + private onCheckRunClick = (checkRun: IRefCheck): void => { this.setState({ checkRunLogsShown: @@ -154,6 +168,7 @@ export class CICheckRunList extends React.PureComponent< loadingLogs={this.state.loadingLogs} showLogs={this.state.checkRunLogsShown === c.id.toString()} onCheckRunClick={this.onCheckRunClick} + onViewOnGitHub={this.viewCheckRunsOnGitHub} /> ) }) diff --git a/app/styles/ui/_ci-check-list-item.scss b/app/styles/ui/_ci-check-list-item.scss index 85d3c120aa..30d8adda14 100644 --- a/app/styles/ui/_ci-check-list-item.scss +++ b/app/styles/ui/_ci-check-list-item.scss @@ -33,30 +33,39 @@ } .ci-check-list-item-logs { - padding: var(--spacing-half); - font-size: var(--font-size-sm); + padding: var(--spacing); border-bottom: var(--base-border); box-shadow: inset 0px 0px 3px -1px grey; - max-height: 200px; - overflow: auto; - word-break: break-word; - pre { - margin: 0; - } + .ci-check-list-item-logs-output { + font-size: var(--font-size-sm); + max-height: 200px; + overflow: auto; + word-break: break-word; - .ci-check-run-log-step { - display: flex; - align-items: center; - .ci-check-status-symbol { - padding: var(--spacing-third); + pre { + margin: 0; } - .ci-check-run-log-step-name { - flex: 1; + + .ci-check-run-log-step { + display: flex; + align-items: center; + .ci-check-status-symbol { + padding: var(--spacing-third); + } + .ci-check-run-log-step-name { + flex: 1; + } + } + + .no-logs-to-display { + padding: var(--spacing-half); } } - .no-logs-to-display { - padding: var(--spacing-half); + .view-on-github { + .button-component { + width: 100%; + } } }