-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PRfD - List Pull Requests UI #8171
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -153,7 +153,7 @@ export const ChangesTreeContainer = ({results, delimiter, uriNavigator, | |
<div>{changesTreeMessage}</div> | ||
<Card> | ||
<Card.Header> | ||
<span className="float-start"> | ||
<span className="float-start w-100"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For some reason, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain please what was wrong? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Basically, overriding bootstrap stuff should only be in case of something related to the theme of the app or something like this, things that are flavors of the app. Should almost never happen. |
||
{(delimiter !== "") && uriNavigator} | ||
</span> | ||
</Card.Header> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
import React from "react"; | ||
|
||
import Nav from "react-bootstrap/Nav"; | ||
import {FileDiffIcon, GitCommitIcon, DatabaseIcon, GitBranchIcon, GitCompareIcon, PlayIcon, GearIcon, TagIcon} from "@primer/octicons-react"; | ||
import {FileDiffIcon, GitCommitIcon, DatabaseIcon, GitBranchIcon, GitPullRequestIcon, GitCompareIcon, PlayIcon, GearIcon, TagIcon} from "@primer/octicons-react"; | ||
|
||
import {useRefs} from "../../hooks/repo"; | ||
import {Link, NavItem} from "../nav"; | ||
import {useRouter} from "../../hooks/router"; | ||
import {RefTypeBranch} from "../../../constants"; | ||
|
||
|
||
// TODO (gilo): this is temp, until PRfD will be ready | ||
const showPulls = false; | ||
|
||
export const RepositoryNavTabs = ({ active }) => { | ||
const { reference } = useRefs(); | ||
|
@@ -59,6 +60,14 @@ export const RepositoryNavTabs = ({ active }) => { | |
<Link active={active === 'tags'} href={`/repositories/${repoId}/tags`} component={NavItem}> | ||
<TagIcon/> Tags | ||
</Link> | ||
{ | ||
// TODO (gilo): this is temp, until PRfD will be ready | ||
showPulls && | ||
<Link active={active === 'pulls'} href={`/repositories/${repoId}/pulls`} component={NavItem}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note - I've used |
||
{/* TODO (gilo): the icon is very similar to the compare icon, consider changing it*/} | ||
<GitPullRequestIcon/> Pull Requests | ||
</Link> | ||
} | ||
<Link active={active === 'compare'} href={withRefAndCompareContext(`/repositories/${repoId}/compare`)} component={NavItem}> | ||
<GitCompareIcon/> Compare | ||
</Link> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is based on the |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import React, {useEffect, useState} from "react"; | ||
import {useOutletContext} from "react-router-dom"; | ||
import Card from "react-bootstrap/Card"; | ||
import ListGroup from "react-bootstrap/ListGroup"; | ||
import Alert from "react-bootstrap/Alert"; | ||
import {Tab, Tabs} from "react-bootstrap"; | ||
import Button from "react-bootstrap/Button"; | ||
import dayjs from "dayjs"; | ||
|
||
import {ActionGroup, AlertError, Loading, PrefixSearchWidget, RefreshButton} from "../../../../lib/components/controls"; | ||
import {pulls} from "../../../../lib/api"; | ||
import {useRefs} from "../../../../lib/hooks/repo"; | ||
import {useAPIWithPagination} from "../../../../lib/hooks/api"; | ||
import {Paginator} from "../../../../lib/components/pagination"; | ||
import {useRouter} from "../../../../lib/hooks/router"; | ||
import {RepoError} from "../error"; | ||
import {Link} from "../../../../lib/components/nav"; | ||
|
||
|
||
const PullWidget = ({repo, pull}) => { | ||
return ( | ||
<ListGroup.Item className="pull-row pt-3 pb-3 clearfix"> | ||
<div className="float-start"> | ||
<h6> | ||
<Link href={{ | ||
pathname: '/repositories/:repoId/pulls/:pullId', | ||
params: {repoId: repo.id, pullId: pull.id} | ||
}}> | ||
<span>{pull.title}</span> | ||
</Link> | ||
</h6> | ||
<small> | ||
Opened {dayjs.unix(pull.created_at).fromNow()} by <strong>{pull.author}</strong> | ||
</small> | ||
</div> | ||
<div className="float-end mt-2"> | ||
<Button variant="secondary" size="sm" disabled={true}>{pull.source_branch}</Button> | ||
<span className="m-2">⇨</span> | ||
<Button variant="secondary" size="sm" disabled={true}>{pull.destination_branch}</Button> | ||
</div> | ||
</ListGroup.Item> | ||
); | ||
}; | ||
|
||
// TODO (gilo): is there a nicer place for this? | ||
const PullStatus = { | ||
open: "open", | ||
closed: "closed", | ||
merged: "merged", | ||
} | ||
|
||
const PullsList = ({repo, after, prefix, onPaginate}) => { | ||
const router = useRouter() | ||
const [refresh, setRefresh] = useState(true); | ||
// TODO: pullState should be persistent in the url and saved as a url param? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. state is a query param in GitHub |
||
const [pullsState, setPullsState] = useState(PullStatus.open); | ||
const {results, error, loading, nextPage} = useAPIWithPagination(async () => { | ||
return pulls.list(repo.id, pullsState, prefix, after); | ||
}, [repo.id, pullsState, prefix, refresh, after]); | ||
|
||
const doRefresh = () => setRefresh(true); | ||
|
||
let content; | ||
|
||
if (loading) content = <Loading/>; | ||
else if (error) content = <AlertError error={error}/>; | ||
else content = (results && !!results.length ? | ||
<> | ||
<Card> | ||
<ListGroup variant="flush"> | ||
{results.map(pull => ( | ||
<PullWidget key={pull.id} repo={repo} pull={pull}/> | ||
))} | ||
</ListGroup> | ||
</Card> | ||
<Paginator onPaginate={onPaginate} nextPage={nextPage} after={after}/> | ||
</> : <Alert variant="info">There aren't any pull requests yet.</Alert> | ||
) | ||
|
||
return ( | ||
<div className="mb-5"> | ||
<div className="position-relative clearfix"> | ||
<div className=""> | ||
<Tabs | ||
defaultActiveKey={pullsState} | ||
id="pulls-tabs" | ||
onSelect={key => setPullsState(key)} | ||
className="mb-3 pt-2" | ||
> | ||
<Tab eventKey={PullStatus.open} title="Open"/> | ||
<Tab eventKey={PullStatus.closed} title="Closed"/> | ||
</Tabs> | ||
</div> | ||
<ActionGroup orientation="right" className="position-absolute top-0 end-0 pb-2"> | ||
<PrefixSearchWidget | ||
defaultValue={router.query.prefix} | ||
text="Find Pull Request" | ||
onFilter={prefix => router.push({ | ||
pathname: '/repositories/:repoId/pulls', | ||
params: {repoId: repo.id}, | ||
query: {prefix} | ||
})}/> | ||
|
||
<RefreshButton onClick={doRefresh}/> | ||
<Button variant="success">Create Pull Request</Button> | ||
</ActionGroup> | ||
</div> | ||
{content} | ||
</div> | ||
); | ||
}; | ||
|
||
|
||
const PullsContainer = () => { | ||
const router = useRouter() | ||
const {repo, loading, error} = useRefs(); | ||
const {after} = router.query; | ||
const routerPfx = router.query.prefix || ""; | ||
|
||
if (loading) return <Loading/>; | ||
if (error) return <RepoError error={error}/>; | ||
|
||
return ( | ||
<PullsList | ||
repo={repo} | ||
after={after || ""} | ||
prefix={routerPfx} | ||
onPaginate={after => { | ||
const query = {after}; | ||
if (router.query.prefix) { | ||
query.prefix = router.query.prefix; | ||
} | ||
router.push({ | ||
pathname: '/repositories/:repoId/pulls', | ||
params: {repoId: repo.id}, | ||
query | ||
}); | ||
}}/> | ||
); | ||
}; | ||
|
||
|
||
const RepositoryPullsPage = () => { | ||
const [setActivePage] = useOutletContext(); | ||
useEffect(() => setActivePage("pulls"), [setActivePage]); | ||
return <PullsContainer/>; | ||
} | ||
|
||
export default RepositoryPullsPage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As written - this is temp, until the API will be ready.