diff --git a/webui/package.json b/webui/package.json
index 84a197d631e..f102d64e216 100644
--- a/webui/package.json
+++ b/webui/package.json
@@ -11,6 +11,7 @@
"scripts": {
"dev": "vite",
"build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build",
+ "build-watch": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build --watch",
"serve": "vite preview",
"test": "vitest run",
"test-watch": "vitest",
diff --git a/webui/src/lib/api/index.js b/webui/src/lib/api/index.js
index 46d9fc2db70..c7da8d3ca11 100644
--- a/webui/src/lib/api/index.js
+++ b/webui/src/lib/api/index.js
@@ -567,6 +567,62 @@ class Tags {
}
+class Pulls {
+ 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);
+ // if (response.status !== 200) {
+ // throw new Error(`could not list pulls: ${await extractError(response)}`);
+ // }
+ // return response.json();
+
+ // TODO: this is for development purposes only
+ console.log("list pulls", {repoId, state, prefix, after, amount})
+ let results = [
+ {
+ "id": "test-pull-1",
+ "title": "Test PR 1",
+ "status": "open",
+ "created_at": 1726575741,
+ "author": "test-user-1",
+ "description": "This is a test PR",
+ "source_branch": "feature-branch-1",
+ "destination_branch": "main"
+ },
+ {
+ "id": "test-pull-2",
+ "title": "Next Test PR 2",
+ "status": "closed",
+ "created_at": 1726402941,
+ "author": "test-user-2",
+ "description": "This is a another test PR",
+ "source_branch": "feature-branch-2",
+ "destination_branch": "main"
+ },
+ {
+ "id": "test-pull-3",
+ "title": "Another Test PR 3",
+ "status": "open",
+ "created_at": 1718454141,
+ "author": "test-user-1",
+ "description": "This is also a test PR",
+ "source_branch": "feature-branch-3",
+ "destination_branch": "feature-branch-1"
+ }
+ ];
+ results = results.filter(pull => pull.status === state);
+ return {
+ "pagination": {
+ "has_more": false,
+ "max_per_page": 1000,
+ "next_offset": "",
+ "results": results.length
+ },
+ "results": results
+ }
+ }
+}
+
// uploadWithProgress uses good ol' XMLHttpRequest because progress indication in fetch() is
// still not well supported across browsers (see https://stackoverflow.com/questions/35711724/upload-progress-indicators-for-fetch).
export const uploadWithProgress = (url, file, method = 'POST', onProgress = null, additionalHeaders = null) => {
@@ -652,7 +708,7 @@ class Objects {
if (response.status === 401) {
return false;
}
-
+
// This is not one of the expected responses
throw new Error(await extractError(response));
}
@@ -1112,6 +1168,7 @@ class Import {
export const repositories = new Repositories();
export const branches = new Branches();
export const tags = new Tags();
+export const pulls = new Pulls();
export const objects = new Objects();
export const commits = new Commits();
export const refs = new Refs();
diff --git a/webui/src/lib/components/controls.jsx b/webui/src/lib/components/controls.jsx
index 2bc4921c3a6..c584e4e2337 100644
--- a/webui/src/lib/components/controls.jsx
+++ b/webui/src/lib/components/controls.jsx
@@ -105,10 +105,10 @@ export const FormattedDate = ({ dateValue, format = "MM/DD/YYYY HH:mm:ss" }) =>
};
-export const ActionGroup = ({ children, orientation = "left" }) => {
+export const ActionGroup = ({ children, orientation = "left", className = "" }) => {
const side = (orientation === 'right') ? 'ms-auto' : '';
return (
-
+
{children}
);
diff --git a/webui/src/lib/components/repository/changes.jsx b/webui/src/lib/components/repository/changes.jsx
index fdc725c65ee..014c750d9f2 100644
--- a/webui/src/lib/components/repository/changes.jsx
+++ b/webui/src/lib/components/repository/changes.jsx
@@ -153,7 +153,7 @@ export const ChangesTreeContainer = ({results, delimiter, uriNavigator,
{changesTreeMessage}
-
+
{(delimiter !== "") && uriNavigator}
diff --git a/webui/src/lib/components/repository/tabs.jsx b/webui/src/lib/components/repository/tabs.jsx
index a5155e0ac27..f050023702f 100644
--- a/webui/src/lib/components/repository/tabs.jsx
+++ b/webui/src/lib/components/repository/tabs.jsx
@@ -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 }) => {
Tags
+ {
+ // TODO (gilo): this is temp, until PRfD will be ready
+ showPulls &&
+
+ {/* TODO (gilo): the icon is very similar to the compare icon, consider changing it*/}
+ Pull Requests
+
+ }
Compare
diff --git a/webui/src/pages/index.jsx b/webui/src/pages/index.jsx
index 14048eec771..1e5af414572 100644
--- a/webui/src/pages/index.jsx
+++ b/webui/src/pages/index.jsx
@@ -18,6 +18,7 @@ import RepositoryCommitsPage from "./repositories/repository/commits";
import RepositoryCommitPage from "./repositories/repository/commits/commit";
import RepositoryBranchesPage from "./repositories/repository/branches";
import RepositoryTagsPage from "./repositories/repository/tags";
+import RepositoryPullsPage from "./repositories/repository/pulls/pulls";
import RepositoryComparePage from "./repositories/repository/compare";
import RepositoryActionsPage from "./repositories/repository/actions";
import RepositoryGeneralSettingsPage from "./repositories/repository/settings/general";
@@ -62,6 +63,7 @@ export const IndexPage = () => {
}/>
}/>
+ }/>
}/>
}/>
diff --git a/webui/src/pages/repositories/repository/commits/index.jsx b/webui/src/pages/repositories/repository/commits/index.jsx
index 4152323e9fd..5a42b0b1ea9 100644
--- a/webui/src/pages/repositories/repository/commits/index.jsx
+++ b/webui/src/pages/repositories/repository/commits/index.jsx
@@ -34,7 +34,7 @@ const CommitWidget = ({ repo, commit }) => {
return (
-
+
{
+ return (
+
+
+
+
+ {pull.title}
+
+
+
+ Opened {dayjs.unix(pull.created_at).fromNow()} by {pull.author}
+
+
+
+
+ ⇨
+
+
+
+ );
+};
+
+// 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?
+ 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 = ;
+ else if (error) content = ;
+ else content = (results && !!results.length ?
+ <>
+
+
+ {results.map(pull => (
+
+ ))}
+
+
+
+ > : There aren't any pull requests yet.
+ )
+
+ return (
+
+
+
+ setPullsState(key)}
+ className="mb-3 pt-2"
+ >
+
+
+
+
+
+ router.push({
+ pathname: '/repositories/:repoId/pulls',
+ params: {repoId: repo.id},
+ query: {prefix}
+ })}/>
+
+
+
+
+
+ {content}
+
+ );
+};
+
+
+const PullsContainer = () => {
+ const router = useRouter()
+ const {repo, loading, error} = useRefs();
+ const {after} = router.query;
+ const routerPfx = router.query.prefix || "";
+
+ if (loading) return ;
+ if (error) return ;
+
+ return (
+ {
+ 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 ;
+}
+
+export default RepositoryPullsPage;
diff --git a/webui/src/pages/repositories/repository/tags.jsx b/webui/src/pages/repositories/repository/tags.jsx
index 22c9efa2375..34c93ef8316 100644
--- a/webui/src/pages/repositories/repository/tags.jsx
+++ b/webui/src/pages/repositories/repository/tags.jsx
@@ -40,7 +40,7 @@ const TagWidget = ({ repo, tag, onDelete }) => {
return (