Seed onboarding project and issue goal context

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-03-24 08:11:09 -05:00
parent 59e29afab5
commit eb73fc747a
8 changed files with 556 additions and 34 deletions

View file

@ -3,28 +3,54 @@ type MaybeId = string | null | undefined;
export function resolveIssueGoalId(input: {
projectId: MaybeId;
goalId: MaybeId;
projectGoalId?: MaybeId;
defaultGoalId: MaybeId;
}): string | null {
if (!input.projectId && !input.goalId) {
return input.defaultGoalId ?? null;
}
return input.goalId ?? null;
if (input.goalId) return input.goalId;
if (input.projectId) return input.projectGoalId ?? null;
return input.defaultGoalId ?? null;
}
export function resolveNextIssueGoalId(input: {
currentProjectId: MaybeId;
currentGoalId: MaybeId;
currentProjectGoalId?: MaybeId;
projectId?: MaybeId;
goalId?: MaybeId;
projectGoalId?: MaybeId;
defaultGoalId: MaybeId;
}): string | null {
const projectId =
input.projectId !== undefined ? input.projectId : input.currentProjectId;
const goalId =
input.goalId !== undefined ? input.goalId : input.currentGoalId;
const projectGoalId =
input.projectGoalId !== undefined
? input.projectGoalId
: projectId
? input.currentProjectGoalId
: null;
if (!projectId && !goalId) {
const resolveFallbackGoalId = (targetProjectId: MaybeId, targetProjectGoalId: MaybeId) => {
if (targetProjectId) return targetProjectGoalId ?? null;
return input.defaultGoalId ?? null;
};
if (input.goalId !== undefined) {
return input.goalId ?? resolveFallbackGoalId(projectId, projectGoalId);
}
return goalId ?? null;
const currentFallbackGoalId = resolveFallbackGoalId(
input.currentProjectId,
input.currentProjectGoalId,
);
const nextFallbackGoalId = resolveFallbackGoalId(projectId, projectGoalId);
if (!input.currentGoalId) {
return nextFallbackGoalId;
}
if (input.currentGoalId === currentFallbackGoalId) {
return nextFallbackGoalId;
}
return input.currentGoalId;
}

View file

@ -101,6 +101,7 @@ type IssueUserContextInput = {
createdAt: Date | string;
updatedAt: Date | string;
};
type ProjectGoalReader = Pick<Db, "select">;
function sameRunLock(checkoutRunId: string | null, actorRunId: string | null) {
if (actorRunId) return checkoutRunId === actorRunId;
@ -113,6 +114,20 @@ function escapeLikePattern(value: string): string {
return value.replace(/[\\%_]/g, "\\$&");
}
async function getProjectDefaultGoalId(
db: ProjectGoalReader,
companyId: string,
projectId: string | null | undefined,
) {
if (!projectId) return null;
const row = await db
.select({ goalId: projects.goalId })
.from(projects)
.where(and(eq(projects.id, projectId), eq(projects.companyId, companyId)))
.then((rows) => rows[0] ?? null);
return row?.goalId ?? null;
}
function touchedByUserCondition(companyId: string, userId: string) {
return sql<boolean>`
(
@ -744,6 +759,7 @@ export function issueService(db: Db) {
}
return db.transaction(async (tx) => {
const defaultCompanyGoal = await getDefaultCompanyGoal(tx, companyId);
const projectGoalId = await getProjectDefaultGoalId(tx, companyId, issueData.projectId);
let executionWorkspaceSettings =
(issueData.executionWorkspaceSettings as Record<string, unknown> | null | undefined) ?? null;
if (executionWorkspaceSettings == null && issueData.projectId) {
@ -795,6 +811,7 @@ export function issueService(db: Db) {
goalId: resolveIssueGoalId({
projectId: issueData.projectId,
goalId: issueData.goalId,
projectGoalId,
defaultGoalId: defaultCompanyGoal?.id ?? null,
}),
...(projectWorkspaceId ? { projectWorkspaceId } : {}),
@ -895,11 +912,21 @@ export function issueService(db: Db) {
return db.transaction(async (tx) => {
const defaultCompanyGoal = await getDefaultCompanyGoal(tx, existing.companyId);
const [currentProjectGoalId, nextProjectGoalId] = await Promise.all([
getProjectDefaultGoalId(tx, existing.companyId, existing.projectId),
getProjectDefaultGoalId(
tx,
existing.companyId,
issueData.projectId !== undefined ? issueData.projectId : existing.projectId,
),
]);
patch.goalId = resolveNextIssueGoalId({
currentProjectId: existing.projectId,
currentGoalId: existing.goalId,
currentProjectGoalId,
projectId: issueData.projectId,
goalId: issueData.goalId,
projectGoalId: nextProjectGoalId,
defaultGoalId: defaultCompanyGoal?.id ?? null,
});
const updated = await tx