Skip to content

Commit

Permalink
PRfD - PR Details page (#8185)
Browse files Browse the repository at this point in the history
* Create Pull Details page

* Create BranchesComparison component

* Use BranchComparison for Compare page

* Revert flag

* Revert refID change

* Change structure

* Extract to files

* Cleanup
  • Loading branch information
itaigilo authored Sep 22, 2024
1 parent b6e5add commit 0b2b1c0
Show file tree
Hide file tree
Showing 11 changed files with 596 additions and 335 deletions.
20 changes: 7 additions & 13 deletions webui/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
export const RefTypeBranch = 'branch';
export const RefTypeCommit = 'commit';
export const RefTypeTag = 'tag';
export enum TreeItemType {
Object,
Prefix,
DeltaLakeTable
}
export enum OtfType {
Delta = "delta",
}
export enum OtfDiffType {
Created = "created",
Dropped = "dropped",
Changed = "changed",
}

export enum TreeRowType {
Object,
Prefix,
Table
}

export enum PullStatus {
open = "open",
closed = "closed",
merged = "merged",
}

60 changes: 44 additions & 16 deletions webui/src/lib/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,29 @@ class Tags {
}

class Pulls {
async get(repoId, pullId) {
// const response = await apiRequest(`/repositories/${encodeURIComponent(repoId)}/pulls/${encodeURIComponent(pullId)}`);
// if (response.status === 404) {
// throw new NotFoundError(`could not find pull ${pullId}`);
// } else if (response.status !== 200) {
// throw new Error(`could not get pullId: ${await extractError(response)}`);
// }
// return response.json();

// TODO: this is for development purposes only
console.log("get pull", {repoId, pullId});
return {
"id": pullId,
"title": "Test PR 1",
"status": "open",
"creation_date": 1726575741,
"author": "test-user-1",
"description": "This is a test PR",
"source_branch": "test-1",
"destination_branch": "main"
}
}

async list(repoId, state = "open", prefix = "", after = "", amount = DEFAULT_LISTING_AMOUNT) {
// const query = qs({prefix, after, amount});
// const response = await apiRequest(`/repositories/${encodeURIComponent(repoId)}/pulls?` + query);
Expand All @@ -577,13 +600,13 @@ class Pulls {
// return response.json();

// TODO: this is for development purposes only
console.log("list pulls", {repoId, state, prefix, after, amount})
console.log("list pulls", {repoId, state, prefix, after, amount});
let results = [
{
"id": "test-pull-1",
"title": "Test PR 1",
"status": "open",
"created_at": 1726575741,
"creation_date": 1726575741,
"author": "test-user-1",
"description": "This is a test PR",
"source_branch": "feature-branch-1",
Expand All @@ -593,7 +616,7 @@ class Pulls {
"id": "test-pull-2",
"title": "Next Test PR 2",
"status": "closed",
"created_at": 1726402941,
"creation_date": 1726402941,
"author": "test-user-2",
"description": "This is a another test PR",
"source_branch": "feature-branch-2",
Expand All @@ -603,7 +626,7 @@ class Pulls {
"id": "test-pull-3",
"title": "Another Test PR 3",
"status": "open",
"created_at": 1718454141,
"creation_date": 1718454141,
"author": "test-user-1",
"description": "This is also a test PR",
"source_branch": "feature-branch-3",
Expand Down Expand Up @@ -634,13 +657,13 @@ export const uploadWithProgress = (url, file, method = 'POST', onProgress = null
}
});
xhr.addEventListener('load', () => {
resolve({
status: xhr.status,
body: xhr.responseText,
contentType: xhr.getResponseHeader('Content-Type'),
etag: xhr.getResponseHeader('ETag'),
contentMD5: xhr.getResponseHeader('Content-MD5'),
})
resolve({
status: xhr.status,
body: xhr.responseText,
contentType: xhr.getResponseHeader('Content-Type'),
etag: xhr.getResponseHeader('ETag'),
contentMD5: xhr.getResponseHeader('Content-MD5'),
})
});
xhr.addEventListener('error', () => reject(new Error('Upload Failed')));
xhr.addEventListener('abort', () => reject(new Error('Upload Aborted')));
Expand Down Expand Up @@ -683,7 +706,7 @@ class Objects {
next: async () => {
const query = qs({prefix, presign, after, amount: MAX_LISTING_AMOUNT});
const response = await apiRequest(
`/repositories/${encodeURIComponent(repoId)}/refs/${encodeURIComponent(ref)}/objects/ls?` + query);
`/repositories/${encodeURIComponent(repoId)}/refs/${encodeURIComponent(ref)}/objects/ls?` + query);
if (response.status === 404) {
throw new NotFoundError(response.message ?? "ref not found");
}
Expand All @@ -693,7 +716,7 @@ class Objects {
const responseBody = await response.json();
const done = !responseBody.pagination.has_more;
if (!done) after = responseBody.pagination.next_offset;
return {page:responseBody.results, done}
return {page: responseBody.results, done}
},
}
}
Expand Down Expand Up @@ -1031,7 +1054,7 @@ class Config {
let cfg;
switch (response.status) {
case 200:
cfg = await response.json();
cfg = await response.json();
return cfg.version_config
default:
throw new Error('Unknown');
Expand Down Expand Up @@ -1106,7 +1129,12 @@ class Staging {
const query = qs({path});
const response = await apiRequest(`/repositories/${encodeURIComponent(repoId)}/branches/${encodeURIComponent(branchId)}/staging/backing?` + query, {
method: 'PUT',
body: JSON.stringify({staging: staging, checksum: checksum, size_bytes: sizeBytes, content_type: contentType})
body: JSON.stringify({
staging: staging,
checksum: checksum,
size_bytes: sizeBytes,
content_type: contentType
})
});
if (response.status !== 200) {
throw new Error(await extractError(response));
Expand Down Expand Up @@ -1135,7 +1163,7 @@ class Import {
"path": source,
"destination": prepend,
"type": "common_prefix",
}],
}],
"commit": {
"message": commitMessage
},
Expand Down
4 changes: 2 additions & 2 deletions webui/src/lib/components/repository/changes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,14 @@ export const TreeEntryPaginator = ({ path, setAfterUpdated, nextPage, depth=0, l
export const ChangesTreeContainer = ({results, delimiter, uriNavigator,
leftDiffRefID, rightDiffRefID, repo, reference, internalRefresh, prefix,
getMore, loading, nextPage, setAfterUpdated, onNavigate, onRevert,
changesTreeMessage= ""}) => {
changesTreeMessage}) => {
if (results.length === 0) {
return <div className="tree-container">
<Alert variant="info">No changes</Alert>
</div>
} else {
return <div className="tree-container">
<div>{changesTreeMessage}</div>
{changesTreeMessage && <div>{changesTreeMessage}</div>}
<Card>
<Card.Header>
<span className="float-start w-100">
Expand Down
164 changes: 164 additions & 0 deletions webui/src/lib/components/repository/compareBranches.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import React, {useState} from "react";
import {refs as refsAPI} from "../../../lib/api";
import Alert from "react-bootstrap/Alert";
import {RefTypeBranch, RefTypeCommit} from "../../../constants";
import {useAPIWithPagination} from "../../hooks/api";
import {appendMoreResults} from "../../../pages/repositories/repository/changes";
import {AlertError, Loading} from "../controls";
import {ChangesTreeContainer, defaultGetMoreChanges} from "./changes";
import {URINavigator} from "./tree";
import CompareBranchesActionsBar from "./compareBranchesActionBar";

const CompareBranches = (
{repo, reference, compareReference, showActionsBar, prefix = "", onSelectRef, onSelectCompare}
) => {
const [internalRefresh, setInternalRefresh] = useState(true);

const [afterUpdated, setAfterUpdated] = useState(""); // state of pagination of the item's children
const [resultsState, setResultsState] = useState({prefix, results: [], pagination: {}}); // current retrieved children of the item

const delimiter = "/"

const {nextPage, loading, error} = useAPIWithPagination(async () => {
if (!repo) return

if (compareReference.id === reference.id) {
return {pagination: {has_more: false}, results: []}; // nothing to compare here.
}

const getMoreResults = () =>
refsAPI.diff(repo.id, reference.id, compareReference.id, afterUpdated, prefix, delimiter);
return await appendMoreResults(resultsState, prefix, afterUpdated, setAfterUpdated, setResultsState, getMoreResults);
}, [repo.id, reference.id, internalRefresh, afterUpdated, delimiter, prefix])

const {results} = resultsState;
const apiResult = {results, loading, error, nextPage};

const isEmptyDiff = (!loading && !error && !!results && results.length === 0);

const doRefresh = () => {
setResultsState({prefix, results: [], pagination: {}})
setInternalRefresh(!internalRefresh)
}

return (
<>
{showActionsBar &&
<CompareBranchesActionsBar
repo={repo}
reference={reference}
onSelectRef={onSelectRef}
compareReference={compareReference}
onSelectCompare={onSelectCompare}
doRefresh={doRefresh}
isEmptyDiff={isEmptyDiff}
/>
}
<BranchChangesList
apiResult={apiResult}
repo={repo}
reference={reference}
compareReference={compareReference}
prefix={prefix}
delimiter={delimiter}
refresh={internalRefresh}
setAfterUpdated={setAfterUpdated}
/>
</>
);
};

const BranchChangesList = (
{apiResult, repo, reference, compareReference, prefix, delimiter, refresh, setAfterUpdated}
) => {
const {results, loading, error, nextPage} = apiResult;

if (loading) return <Loading/>;
if (error) return <AlertError error={error}/>;

const changesTreeMessage =
<p>
Showing changes between <strong>{reference.id}</strong> {""}
and <strong>{compareReference.id}</strong>
</p>

if (compareReference.id === reference.id) {
return <Alert variant="warning">
<Alert.Heading>There isn’t anything to compare.</Alert.Heading>
You’ll need to use two different sources to get a valid comparison.
</Alert>;
}

return <ChangesTreeContainer
results={results}
reference={reference}
leftDiffRefID={getRefID(reference)}
rightDiffRefID={getRefID(compareReference)}
repo={repo}
delimiter={delimiter}
uriNavigator={CompareURINavigator(prefix, reference, compareReference, repo)}
internalReferesh={refresh}
prefix={prefix}
getMore={defaultGetMoreChanges(repo, reference.id, compareReference.id, delimiter)}
nextPage={nextPage}
setAfterUpdated={setAfterUpdated}
onNavigate={getNavigatorToComparePage(repo, reference, compareReference)}
changesTreeMessage={changesTreeMessage}
/>;
};

function getURINavigatorRelativeTitle(from, to) {
let fromId = from.id;
let toId = to.id;
if (from.type === RefTypeCommit) {
fromId = fromId.substr(0, 12);
}
if (to.type === RefTypeCommit) {
toId = toId.substr(0, 12);
}
return `${fromId}...${toId}`
}

const CompareURINavigator = (prefix, reference, compareReference, repo) =>
<URINavigator
path={prefix}
reference={reference}
relativeTo={getURINavigatorRelativeTitle(reference, compareReference)}
repo={repo}
pathURLBuilder={(params, query) => {
const q = {
delimiter: "/",
prefix: query.path,
};
if (compareReference) {
q.compare = compareReference.id;
}
if (reference) {
q.ref = reference.id;
}
return {
pathname: '/repositories/:repoId/compare',
params: {repoId: repo.id},
query: q
};
}}/>;

const getNavigatorToComparePage = (repo, ref, compareRef) => entry => ({
pathname: `/repositories/:repoId/compare`,
params: {repoId: repo.id},
query: {
ref: ref.id,
compare: compareRef.id,
prefix: entry.path,
}
});

function getRefID(reference) {
let refID = reference.id;
if (reference.type === RefTypeBranch) {
refID += "@";
}
return refID;
}

export default CompareBranches;
Loading

0 comments on commit 0b2b1c0

Please sign in to comment.