feat: hydrate persisted PR details on task disclosure (#3055)
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
import type { StateCreator } from "zustand";
|
||||
import type { GitHubSlice, GitHubSliceState } from "./types";
|
||||
import type { GitHubSlice, GitHubSliceState, TaskPRScope } from "./types";
|
||||
|
||||
export const defaultGitHubState: GitHubSliceState = {
|
||||
githubStatus: { byWorkspaceId: {} },
|
||||
githubAppRegistrations: { byWorkspaceId: {} },
|
||||
taskPRs: { byTaskId: {} },
|
||||
taskPRs: {
|
||||
byTaskId: {},
|
||||
workspaceId: null,
|
||||
workspaceContextGeneration: 0,
|
||||
deletedAssociationIdsByTaskId: {},
|
||||
},
|
||||
taskIssues: { workspaceId: null, byTaskId: {} },
|
||||
pendingPrUrlByTaskId: { byTaskId: {} },
|
||||
prWatches: { items: [], loaded: false, loading: false },
|
||||
@@ -120,6 +125,30 @@ function clearPendingForTaskPR(
|
||||
}
|
||||
}
|
||||
|
||||
function applyTaskPRScope(draft: GitHubSlice, scope?: TaskPRScope): void {
|
||||
if (!scope) return;
|
||||
const changed =
|
||||
draft.taskPRs.workspaceId !== scope.workspaceId ||
|
||||
draft.taskPRs.workspaceContextGeneration !== scope.workspaceContextGeneration;
|
||||
if (changed) {
|
||||
draft.taskPRs.byTaskId = {};
|
||||
draft.taskPRs.deletedAssociationIdsByTaskId = {};
|
||||
}
|
||||
draft.taskPRs.workspaceId = scope.workspaceId;
|
||||
draft.taskPRs.workspaceContextGeneration = scope.workspaceContextGeneration;
|
||||
}
|
||||
|
||||
function clearTaskPRDeletionTombstone(draft: GitHubSlice, taskId: string, associationId: string) {
|
||||
const deletedByTask = draft.taskPRs.deletedAssociationIdsByTaskId;
|
||||
if (!deletedByTask) return;
|
||||
const deleted = deletedByTask[taskId];
|
||||
if (!deleted) return;
|
||||
delete deleted[associationId];
|
||||
if (Object.keys(deleted).length === 0) {
|
||||
delete deletedByTask[taskId];
|
||||
}
|
||||
}
|
||||
|
||||
function createTaskPRActions(
|
||||
set: ImmerSet,
|
||||
): Pick<
|
||||
@@ -132,12 +161,19 @@ function createTaskPRActions(
|
||||
| "upsertTaskIssue"
|
||||
> {
|
||||
return {
|
||||
setTaskPRs: (prs) =>
|
||||
setTaskPRs: (prs, scope) =>
|
||||
set((draft) => {
|
||||
applyTaskPRScope(draft, scope);
|
||||
draft.taskPRs.byTaskId = prs;
|
||||
draft.taskPRs.deletedAssociationIdsByTaskId = {};
|
||||
}),
|
||||
removeTaskPR: (taskId, associationId) =>
|
||||
removeTaskPR: (taskId, associationId, scope) =>
|
||||
set((draft) => {
|
||||
applyTaskPRScope(draft, scope);
|
||||
const deletedByTask = (draft.taskPRs.deletedAssociationIdsByTaskId ??= {});
|
||||
const deleted = deletedByTask[taskId] ?? {};
|
||||
deleted[associationId] = true;
|
||||
deletedByTask[taskId] = deleted;
|
||||
const current = draft.taskPRs.byTaskId[taskId];
|
||||
if (!Array.isArray(current)) return;
|
||||
const remaining = current.filter((pr) => pr.id !== associationId);
|
||||
@@ -155,8 +191,10 @@ function createTaskPRActions(
|
||||
draft.taskIssues.workspaceId = workspaceId;
|
||||
draft.taskIssues.byTaskId[issue.task_id] = issue;
|
||||
}),
|
||||
setTaskPR: (taskId, pr) =>
|
||||
setTaskPR: (taskId, pr, scope) =>
|
||||
set((draft) => {
|
||||
applyTaskPRScope(draft, scope);
|
||||
clearTaskPRDeletionTombstone(draft, taskId, pr.id);
|
||||
// Upsert by (repository_id, pr_number) so multi-branch tasks can
|
||||
// hold N PRs on the same repo as siblings. Keying on
|
||||
// repository_id alone collapses every PR for that repo onto one
|
||||
|
||||
Reference in New Issue
Block a user