feat(ui): rich forge entity views — commits, files/diff, timeline, checks, metadata chips
- server: new read routes for PR/MR commits, timeline, reviews, commit-statuses across github/gitlab/gitea; enrich PR/issue summaries with labels/assignees/milestone/commentsCount - ui: forge facade gains getCommits/getTimeline/getChecks; shared ForgeEntityDetailView + section components; mounted into PR/MR views and issue sections
This commit is contained in:
@@ -6,11 +6,14 @@ import type {
|
||||
GiteaIssueGetResult,
|
||||
GiteaIssuesListResult,
|
||||
GiteaPullRequest,
|
||||
GiteaPullRequestCommitsResult,
|
||||
GiteaPullRequestContextResult,
|
||||
GiteaPullRequestCreateInput,
|
||||
GiteaPullRequestMergeInput,
|
||||
GiteaPullRequestMergeResult,
|
||||
GiteaPullRequestReviewsResult,
|
||||
GiteaPullRequestsListResult,
|
||||
GiteaPullRequestStatusesResult,
|
||||
GiteaPullRequestUpdateInput,
|
||||
GiteaUserSummary,
|
||||
} from '@openchamber/ui/lib/api/types';
|
||||
@@ -186,6 +189,54 @@ export const createWebGiteaAPI = ({ urls }: WebGiteaAPIOptions): GiteaAPI => ({
|
||||
return payload;
|
||||
},
|
||||
|
||||
async prCommits(directory: string, number: number, options?: { owner?: string; repo?: string }): Promise<GiteaPullRequestCommitsResult> {
|
||||
const params = new URLSearchParams({ directory, number: String(number) });
|
||||
if (options?.owner) {
|
||||
params.set('owner', options.owner);
|
||||
}
|
||||
if (options?.repo) {
|
||||
params.set('repo', options.repo);
|
||||
}
|
||||
const response = await runtimeFetch(urls.api('/api/gitea/prs/commits', params), { method: 'GET', headers: { Accept: 'application/json' } });
|
||||
const payload = await jsonOrNull<GiteaPullRequestCommitsResult & { error?: string }>(response);
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load Gitea pull request commits');
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
async prStatuses(directory: string, number: number, options?: { owner?: string; repo?: string }): Promise<GiteaPullRequestStatusesResult> {
|
||||
const params = new URLSearchParams({ directory, number: String(number) });
|
||||
if (options?.owner) {
|
||||
params.set('owner', options.owner);
|
||||
}
|
||||
if (options?.repo) {
|
||||
params.set('repo', options.repo);
|
||||
}
|
||||
const response = await runtimeFetch(urls.api('/api/gitea/prs/statuses', params), { method: 'GET', headers: { Accept: 'application/json' } });
|
||||
const payload = await jsonOrNull<GiteaPullRequestStatusesResult & { error?: string }>(response);
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load Gitea pull request statuses');
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
async prReviews(directory: string, number: number, options?: { owner?: string; repo?: string }): Promise<GiteaPullRequestReviewsResult> {
|
||||
const params = new URLSearchParams({ directory, number: String(number) });
|
||||
if (options?.owner) {
|
||||
params.set('owner', options.owner);
|
||||
}
|
||||
if (options?.repo) {
|
||||
params.set('repo', options.repo);
|
||||
}
|
||||
const response = await runtimeFetch(urls.api('/api/gitea/prs/reviews', params), { method: 'GET', headers: { Accept: 'application/json' } });
|
||||
const payload = await jsonOrNull<GiteaPullRequestReviewsResult & { error?: string }>(response);
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load Gitea pull request reviews');
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
async prCreate(input: GiteaPullRequestCreateInput): Promise<GiteaPullRequest> {
|
||||
const response = await runtimeFetch('/api/gitea/pr/create', {
|
||||
method: 'POST',
|
||||
|
||||
@@ -5,6 +5,8 @@ import type {
|
||||
GitHubIssueGetResult,
|
||||
GitHubIssuesListResult,
|
||||
GitHubPullRequestContextResult,
|
||||
GitHubPullRequestCommitsResult,
|
||||
GitHubPullRequestTimelineResult,
|
||||
GitHubPullRequestsListResult,
|
||||
GitHubPullRequest,
|
||||
GitHubPullRequestCreateInput,
|
||||
@@ -295,4 +297,32 @@ export const createWebGitHubAPI = ({ urls }: WebGitHubAPIOptions): GitHubAPI =>
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
async prCommits(directory: string, number: number, options?: { sourceRepo?: { owner: string; repo: string } | null }): Promise<GitHubPullRequestCommitsResult> {
|
||||
const params = new URLSearchParams({ directory, number: String(number) });
|
||||
if (options?.sourceRepo?.owner && options.sourceRepo.repo) {
|
||||
params.set('owner', options.sourceRepo.owner);
|
||||
params.set('repo', options.sourceRepo.repo);
|
||||
}
|
||||
const response = await runtimeFetch(urls.api('/api/github/pulls/commits', params), { method: 'GET', headers: { Accept: 'application/json' } });
|
||||
const payload = await jsonOrNull<GitHubPullRequestCommitsResult & { error?: string }>(response);
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load pull request commits');
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
async prTimeline(directory: string, number: number, options?: { sourceRepo?: { owner: string; repo: string } | null }): Promise<GitHubPullRequestTimelineResult> {
|
||||
const params = new URLSearchParams({ directory, number: String(number) });
|
||||
if (options?.sourceRepo?.owner && options.sourceRepo.repo) {
|
||||
params.set('owner', options.sourceRepo.owner);
|
||||
params.set('repo', options.sourceRepo.repo);
|
||||
}
|
||||
const response = await runtimeFetch(urls.api('/api/github/pulls/timeline', params), { method: 'GET', headers: { Accept: 'application/json' } });
|
||||
const payload = await jsonOrNull<GitHubPullRequestTimelineResult & { error?: string }>(response);
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load pull request timeline');
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -6,12 +6,14 @@ import type {
|
||||
GitLabIssueGetResult,
|
||||
GitLabIssuesListResult,
|
||||
GitLabMergeRequest,
|
||||
GitLabMergeRequestCommitsResult,
|
||||
GitLabMergeRequestContextResult,
|
||||
GitLabMergeRequestCreateInput,
|
||||
GitLabMergeRequestCreateResult,
|
||||
GitLabMergeRequestMergeInput,
|
||||
GitLabMergeRequestMergeResult,
|
||||
GitLabMergeRequestsListResult,
|
||||
GitLabMergeRequestTimelineResult,
|
||||
GitLabMergeRequestUpdateInput,
|
||||
GitLabMergeRequestUpdateResult,
|
||||
GitLabUserSummary,
|
||||
@@ -182,6 +184,38 @@ export const createWebGitLabAPI = ({ urls }: WebGitLabAPIOptions): GitLabAPI =>
|
||||
return payload;
|
||||
},
|
||||
|
||||
async mrCommits(directory: string, number: number, options?: { namespace?: string; project?: string }): Promise<GitLabMergeRequestCommitsResult> {
|
||||
const params = new URLSearchParams({ directory, number: String(number) });
|
||||
if (options?.namespace) {
|
||||
params.set('namespace', options.namespace);
|
||||
}
|
||||
if (options?.project) {
|
||||
params.set('project', options.project);
|
||||
}
|
||||
const response = await runtimeFetch(urls.api('/api/gitlab/mrs/commits', params), { method: 'GET', headers: { Accept: 'application/json' } });
|
||||
const payload = await jsonOrNull<GitLabMergeRequestCommitsResult & { error?: string }>(response);
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load GitLab merge request commits');
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
async mrTimeline(directory: string, number: number, options?: { namespace?: string; project?: string }): Promise<GitLabMergeRequestTimelineResult> {
|
||||
const params = new URLSearchParams({ directory, number: String(number) });
|
||||
if (options?.namespace) {
|
||||
params.set('namespace', options.namespace);
|
||||
}
|
||||
if (options?.project) {
|
||||
params.set('project', options.project);
|
||||
}
|
||||
const response = await runtimeFetch(urls.api('/api/gitlab/mrs/timeline', params), { method: 'GET', headers: { Accept: 'application/json' } });
|
||||
const payload = await jsonOrNull<GitLabMergeRequestTimelineResult & { error?: string }>(response);
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load GitLab merge request timeline');
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
async mrCreate(input: GitLabMergeRequestCreateInput): Promise<GitLabMergeRequest> {
|
||||
const response = await runtimeFetch('/api/gitlab/mrs/create', {
|
||||
method: 'POST',
|
||||
|
||||
Reference in New Issue
Block a user