feat: enhance OKR management by adding permission checks for editing and deleting, and updating OKR forms to handle key results more effectively
Some checks failed
Deploy with Docker Compose / deploy (push) Failing after 4m44s

This commit is contained in:
Julien Froidefond
2026-01-07 16:48:23 +01:00
parent 5f661c8bfd
commit ca9b68ebbd
8 changed files with 562 additions and 100 deletions

View File

@@ -1,5 +1,5 @@
import { prisma } from '@/services/database';
import type { CreateOKRInput, UpdateOKRInput, UpdateKeyResultInput, OKRStatus, KeyResultStatus } from '@/lib/types';
import type { UpdateOKRInput, OKRStatus, KeyResultStatus } from '@/lib/types';
export async function createOKR(
teamMemberId: string,
@@ -183,30 +183,105 @@ export async function getUserOKRs(userId: string) {
);
}
export async function updateOKR(okrId: string, data: UpdateOKRInput) {
const okr = await prisma.oKR.update({
where: { id: okrId },
data: {
...(data.objective !== undefined && { objective: data.objective }),
...(data.description !== undefined && { description: data.description || null }),
...(data.period !== undefined && { period: data.period }),
...(data.startDate !== undefined && { startDate: data.startDate }),
...(data.endDate !== undefined && { endDate: data.endDate }),
...(data.status !== undefined && { status: data.status }),
},
include: {
keyResults: {
orderBy: {
order: 'asc',
export async function updateOKR(
okrId: string,
data: UpdateOKRInput,
keyResultsUpdates?: {
create?: Array<{ title: string; targetValue: number; unit: string; order: number }>;
update?: Array<{
id: string;
title?: string;
targetValue?: number;
unit?: string;
order?: number;
}>;
delete?: string[];
}
) {
return prisma.$transaction(async (tx) => {
// Update OKR
await tx.oKR.update({
where: { id: okrId },
data: {
...(data.objective !== undefined && { objective: data.objective }),
...(data.description !== undefined && { description: data.description || null }),
...(data.period !== undefined && { period: data.period }),
...(data.startDate !== undefined && { startDate: data.startDate }),
...(data.endDate !== undefined && { endDate: data.endDate }),
...(data.status !== undefined && { status: data.status }),
},
});
// Handle Key Results updates if provided
if (keyResultsUpdates) {
// Delete Key Results
if (keyResultsUpdates.delete && keyResultsUpdates.delete.length > 0) {
await tx.keyResult.deleteMany({
where: {
id: { in: keyResultsUpdates.delete },
okrId,
},
});
}
// Create new Key Results
if (keyResultsUpdates.create && keyResultsUpdates.create.length > 0) {
await Promise.all(
keyResultsUpdates.create.map((kr) =>
tx.keyResult.create({
data: {
okrId,
title: kr.title,
targetValue: kr.targetValue,
currentValue: 0,
unit: kr.unit || '%',
status: 'NOT_STARTED',
order: kr.order,
},
})
)
);
}
// Update existing Key Results
if (keyResultsUpdates.update && keyResultsUpdates.update.length > 0) {
await Promise.all(
keyResultsUpdates.update.map((kr) =>
tx.keyResult.update({
where: { id: kr.id },
data: {
...(kr.title !== undefined && { title: kr.title }),
...(kr.targetValue !== undefined && { targetValue: kr.targetValue }),
...(kr.unit !== undefined && { unit: kr.unit }),
...(kr.order !== undefined && { order: kr.order }),
},
})
)
);
}
}
// Fetch updated OKR with Key Results
const updatedOkr = await tx.oKR.findUnique({
where: { id: okrId },
include: {
keyResults: {
orderBy: {
order: 'asc',
},
},
},
},
});
});
return {
...okr,
progress: calculateOKRProgressFromKeyResults(okr.keyResults),
};
if (!updatedOkr) {
throw new Error('OKR not found after update');
}
return {
...updatedOkr,
progress: calculateOKRProgressFromKeyResults(updatedOkr.keyResults),
};
});
}
export async function deleteOKR(okrId: string) {
@@ -216,6 +291,47 @@ export async function deleteOKR(okrId: string) {
});
}
export async function createKeyResult(
okrId: string,
title: string,
targetValue: number,
unit: string,
order: number
) {
return prisma.keyResult.create({
data: {
okrId,
title,
targetValue,
currentValue: 0,
unit: unit || '%',
status: 'NOT_STARTED',
order,
},
});
}
export async function updateKeyResultMetadata(
krId: string,
data: { title?: string; targetValue?: number; unit?: string; order?: number }
) {
return prisma.keyResult.update({
where: { id: krId },
data: {
...(data.title !== undefined && { title: data.title }),
...(data.targetValue !== undefined && { targetValue: data.targetValue }),
...(data.unit !== undefined && { unit: data.unit }),
...(data.order !== undefined && { order: data.order }),
},
});
}
export async function deleteKeyResult(krId: string) {
return prisma.keyResult.delete({
where: { id: krId },
});
}
export async function updateKeyResult(krId: string, currentValue: number, notes: string | null) {
// Auto-update status based on progress
const kr = await prisma.keyResult.findUnique({
@@ -293,7 +409,9 @@ export function calculateOKRProgress(okrId: string): Promise<number> {
});
}
function calculateOKRProgressFromKeyResults(keyResults: Array<{ currentValue: number; targetValue: number }>): number {
function calculateOKRProgressFromKeyResults(
keyResults: Array<{ currentValue: number; targetValue: number }>
): number {
if (keyResults.length === 0) {
return 0;
}
@@ -305,4 +423,3 @@ function calculateOKRProgressFromKeyResults(keyResults: Array<{ currentValue: nu
return Math.round(totalProgress / keyResults.length);
}