Missions Corrections
This commit is contained in:
parent
98f0f8532a
commit
5e3289f0e1
@ -54,7 +54,13 @@ export async function POST(request: Request) {
|
||||
logger.debug('Received mission-created data', {
|
||||
hasMissionId: !!body.missionId,
|
||||
hasName: !!body.name,
|
||||
hasCreatorId: !!body.creatorId
|
||||
hasCreatorId: !!body.creatorId,
|
||||
gitRepoUrl: body.gitRepoUrl,
|
||||
leantimeProjectId: body.leantimeProjectId,
|
||||
documentationCollectionId: body.documentationCollectionId,
|
||||
rocketchatChannelId: body.rocketchatChannelId,
|
||||
gitRepoUrlType: typeof body.gitRepoUrl,
|
||||
rocketchatChannelIdType: typeof body.rocketchatChannelId,
|
||||
});
|
||||
|
||||
// Validation des champs requis
|
||||
@ -125,28 +131,71 @@ export async function POST(request: Request) {
|
||||
rocketChatChannelId?: string | null;
|
||||
} = {};
|
||||
|
||||
// Helper function to check if a value is valid
|
||||
const isValidValue = (value: any, type?: 'gitea' | 'outline' | 'rocketchat' | 'leantime'): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
if (trimmed === '' || trimmed === '0' || trimmed === 'null' || trimmed === 'undefined') return false;
|
||||
|
||||
// Additional validation based on type
|
||||
if (type === 'gitea') {
|
||||
// Reject Outline collection paths (they start with /collection/)
|
||||
if (trimmed.startsWith('/collection/')) return false;
|
||||
// Reject if it doesn't look like a URL or repo path
|
||||
if (!trimmed.includes('http') && !trimmed.includes('/') && trimmed.length < 3) return false;
|
||||
}
|
||||
if (type === 'outline') {
|
||||
// Outline IDs should be UUIDs or paths
|
||||
if (trimmed.startsWith('/collection/')) return true; // This is valid for Outline
|
||||
}
|
||||
if (type === 'rocketchat') {
|
||||
// RocketChat channel IDs should be alphanumeric strings
|
||||
if (trimmed.length < 3) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (typeof value === 'number') return value !== 0;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Mapper les champs N8N vers notre schéma Prisma
|
||||
// Vérifier que les valeurs ne sont pas des chaînes vides
|
||||
// Vérifier que les valeurs ne sont pas des chaînes vides, "0", "null", "undefined", etc.
|
||||
// ET vérifier qu'elles correspondent au bon type (pas de mélange Gitea/Outline)
|
||||
if (body.gitRepoUrl !== undefined) {
|
||||
updateData.giteaRepositoryUrl = (body.gitRepoUrl && body.gitRepoUrl.trim() !== '') ? body.gitRepoUrl : null;
|
||||
logger.debug('Updating giteaRepositoryUrl', { hasUrl: !!updateData.giteaRepositoryUrl, value: body.gitRepoUrl });
|
||||
const isValid = isValidValue(body.gitRepoUrl, 'gitea');
|
||||
updateData.giteaRepositoryUrl = isValid ? body.gitRepoUrl : null;
|
||||
logger.debug('Updating giteaRepositoryUrl', {
|
||||
hasUrl: !!updateData.giteaRepositoryUrl,
|
||||
value: body.gitRepoUrl,
|
||||
isValid,
|
||||
isOutlinePath: typeof body.gitRepoUrl === 'string' && body.gitRepoUrl.trim().startsWith('/collection/')
|
||||
});
|
||||
}
|
||||
|
||||
if (body.leantimeProjectId !== undefined) {
|
||||
// N8N peut retourner un number, on le convertit en string
|
||||
const projectId = body.leantimeProjectId ? String(body.leantimeProjectId).trim() : '';
|
||||
updateData.leantimeProjectId = projectId !== '' ? projectId : null;
|
||||
logger.debug('Updating leantimeProjectId', { hasId: !!updateData.leantimeProjectId, value: body.leantimeProjectId });
|
||||
const isValid = isValidValue(projectId, 'leantime');
|
||||
updateData.leantimeProjectId = isValid ? projectId : null;
|
||||
logger.debug('Updating leantimeProjectId', { hasId: !!updateData.leantimeProjectId, value: body.leantimeProjectId, isValid });
|
||||
}
|
||||
|
||||
if (body.documentationCollectionId !== undefined) {
|
||||
updateData.outlineCollectionId = (body.documentationCollectionId && body.documentationCollectionId.trim() !== '') ? body.documentationCollectionId : null;
|
||||
logger.debug('Updating outlineCollectionId', { hasId: !!updateData.outlineCollectionId, value: body.documentationCollectionId });
|
||||
const isValid = isValidValue(body.documentationCollectionId, 'outline');
|
||||
updateData.outlineCollectionId = isValid ? body.documentationCollectionId : null;
|
||||
logger.debug('Updating outlineCollectionId', { hasId: !!updateData.outlineCollectionId, value: body.documentationCollectionId, isValid });
|
||||
}
|
||||
|
||||
if (body.rocketchatChannelId !== undefined) {
|
||||
updateData.rocketChatChannelId = (body.rocketchatChannelId && body.rocketchatChannelId.trim() !== '') ? body.rocketchatChannelId : null;
|
||||
logger.debug('Updating rocketChatChannelId', { hasId: !!updateData.rocketChatChannelId, value: body.rocketchatChannelId });
|
||||
const isValid = isValidValue(body.rocketchatChannelId, 'rocketchat');
|
||||
updateData.rocketChatChannelId = isValid ? body.rocketchatChannelId : null;
|
||||
logger.debug('Updating rocketChatChannelId', {
|
||||
hasId: !!updateData.rocketChatChannelId,
|
||||
value: body.rocketchatChannelId,
|
||||
isValid,
|
||||
valueType: typeof body.rocketchatChannelId
|
||||
});
|
||||
}
|
||||
|
||||
// Vérifier qu'il y a au moins un champ à mettre à jour
|
||||
|
||||
@ -384,14 +384,50 @@ export default function MissionTabDetailPage() {
|
||||
)}
|
||||
|
||||
{/* Ressources Métiers */}
|
||||
{((mission.rocketChatChannelId && mission.rocketChatChannelId.trim() !== '') ||
|
||||
(mission.outlineCollectionId && mission.outlineCollectionId.trim() !== '') ||
|
||||
(mission.giteaRepositoryUrl && mission.giteaRepositoryUrl.trim() !== '') ||
|
||||
(mission.leantimeProjectId && mission.leantimeProjectId.toString().trim() !== '')) && (
|
||||
{(() => {
|
||||
// Helper function to check if a value is valid (not null, not undefined, not empty string, not "0", not "null", not "undefined")
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
if (typeof value === 'number') return value !== 0;
|
||||
return true;
|
||||
};
|
||||
|
||||
const hasRocketChat = isValid(mission.rocketChatChannelId);
|
||||
const hasOutline = isValid(mission.outlineCollectionId);
|
||||
const hasGitea = isValid(mission.giteaRepositoryUrl);
|
||||
const hasLeantime = isValid(mission.leantimeProjectId);
|
||||
|
||||
console.log('Ressources Métiers check (mission-tab):', {
|
||||
hasRocketChat,
|
||||
hasOutline,
|
||||
hasGitea,
|
||||
hasLeantime,
|
||||
rocketChatValue: mission.rocketChatChannelId,
|
||||
outlineValue: mission.outlineCollectionId,
|
||||
giteaValue: mission.giteaRepositoryUrl,
|
||||
leantimeValue: mission.leantimeProjectId,
|
||||
});
|
||||
|
||||
return hasRocketChat || hasOutline || hasGitea || hasLeantime;
|
||||
})() && (
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-100 p-6">
|
||||
<h2 className="text-lg font-semibold text-gray-900 mb-4">Ressources Métiers</h2>
|
||||
<div className="space-y-3">
|
||||
{mission.rocketChatChannelId && mission.rocketChatChannelId.trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.rocketChatChannelId);
|
||||
})() && (() => {
|
||||
// Build RocketChat URL: parole.slm-lab.net/channel/[channelId]
|
||||
// If it's already a full URL, use it; otherwise build from ID
|
||||
const rocketChatUrl = mission.rocketChatChannelId.startsWith('http')
|
||||
@ -416,7 +452,17 @@ export default function MissionTabDetailPage() {
|
||||
);
|
||||
})()}
|
||||
|
||||
{mission.outlineCollectionId && mission.outlineCollectionId.trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.outlineCollectionId);
|
||||
})() && (() => {
|
||||
// Build Outline URL: chapitre.slm-lab.net/collection/[collectionId]
|
||||
// If it's already a full URL, use it; otherwise build from ID
|
||||
const outlineUrl = mission.outlineCollectionId.startsWith('http')
|
||||
@ -441,7 +487,17 @@ export default function MissionTabDetailPage() {
|
||||
);
|
||||
})()}
|
||||
|
||||
{mission.giteaRepositoryUrl && mission.giteaRepositoryUrl.trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.giteaRepositoryUrl);
|
||||
})() && (() => {
|
||||
// Use mission name (sanitized) as repo name
|
||||
const repoName = sanitizeMissionName(mission.name);
|
||||
|
||||
@ -472,7 +528,18 @@ export default function MissionTabDetailPage() {
|
||||
);
|
||||
})()}
|
||||
|
||||
{mission.leantimeProjectId && mission.leantimeProjectId.toString().trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
if (typeof value === 'number') return value !== 0;
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.leantimeProjectId);
|
||||
})() && (() => {
|
||||
// Build Leantime URL: agilite.slm-lab.net/projects/showProject/[projectId]
|
||||
// If it's already a full URL, use it; otherwise build from ID
|
||||
const leantimeUrl = mission.leantimeProjectId.startsWith('http')
|
||||
|
||||
@ -94,6 +94,16 @@ export default function MissionDetailPage() {
|
||||
}
|
||||
const data = await response.json();
|
||||
console.log("Mission details:", data);
|
||||
console.log("Integration IDs:", {
|
||||
rocketChatChannelId: data.rocketChatChannelId,
|
||||
outlineCollectionId: data.outlineCollectionId,
|
||||
giteaRepositoryUrl: data.giteaRepositoryUrl,
|
||||
leantimeProjectId: data.leantimeProjectId,
|
||||
rocketChatType: typeof data.rocketChatChannelId,
|
||||
outlineType: typeof data.outlineCollectionId,
|
||||
giteaType: typeof data.giteaRepositoryUrl,
|
||||
leantimeType: typeof data.leantimeProjectId,
|
||||
});
|
||||
setMission(data);
|
||||
setEditedPlan(data.actionPlan || "");
|
||||
} catch (error) {
|
||||
@ -604,14 +614,50 @@ export default function MissionDetailPage() {
|
||||
)}
|
||||
|
||||
{/* Ressources Métiers */}
|
||||
{((mission.rocketChatChannelId && mission.rocketChatChannelId.trim() !== '') ||
|
||||
(mission.outlineCollectionId && mission.outlineCollectionId.trim() !== '') ||
|
||||
(mission.giteaRepositoryUrl && mission.giteaRepositoryUrl.trim() !== '') ||
|
||||
(mission.leantimeProjectId && mission.leantimeProjectId.toString().trim() !== '')) && (
|
||||
{(() => {
|
||||
// Helper function to check if a value is valid (not null, not undefined, not empty string, not "0", not "null", not "undefined")
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
if (typeof value === 'number') return value !== 0;
|
||||
return true;
|
||||
};
|
||||
|
||||
const hasRocketChat = isValid(mission.rocketChatChannelId);
|
||||
const hasOutline = isValid(mission.outlineCollectionId);
|
||||
const hasGitea = isValid(mission.giteaRepositoryUrl);
|
||||
const hasLeantime = isValid(mission.leantimeProjectId);
|
||||
|
||||
console.log('Ressources Métiers check:', {
|
||||
hasRocketChat,
|
||||
hasOutline,
|
||||
hasGitea,
|
||||
hasLeantime,
|
||||
rocketChatValue: mission.rocketChatChannelId,
|
||||
outlineValue: mission.outlineCollectionId,
|
||||
giteaValue: mission.giteaRepositoryUrl,
|
||||
leantimeValue: mission.leantimeProjectId,
|
||||
});
|
||||
|
||||
return hasRocketChat || hasOutline || hasGitea || hasLeantime;
|
||||
})() && (
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-100 p-6">
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">Ressources Métiers</h2>
|
||||
<div className="space-y-3">
|
||||
{mission.rocketChatChannelId && mission.rocketChatChannelId.trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.rocketChatChannelId);
|
||||
})() && (() => {
|
||||
// Build RocketChat URL: parole.slm-lab.net/channel/[channelId]
|
||||
// If it's already a full URL, use it; otherwise build from ID
|
||||
const rocketChatUrl = mission.rocketChatChannelId.startsWith('http')
|
||||
@ -636,7 +682,17 @@ export default function MissionDetailPage() {
|
||||
);
|
||||
})()}
|
||||
|
||||
{mission.outlineCollectionId && mission.outlineCollectionId.trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.outlineCollectionId);
|
||||
})() && (() => {
|
||||
// Build Outline URL: chapitre.slm-lab.net/collection/[collectionId]
|
||||
// If it's already a full URL, use it; otherwise build from ID
|
||||
const outlineUrl = mission.outlineCollectionId.startsWith('http')
|
||||
@ -661,7 +717,17 @@ export default function MissionDetailPage() {
|
||||
);
|
||||
})()}
|
||||
|
||||
{mission.giteaRepositoryUrl && mission.giteaRepositoryUrl.trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.giteaRepositoryUrl);
|
||||
})() && (() => {
|
||||
// Use mission name (sanitized) as repo name
|
||||
const repoName = sanitizeMissionName(mission.name);
|
||||
|
||||
@ -692,7 +758,18 @@ export default function MissionDetailPage() {
|
||||
);
|
||||
})()}
|
||||
|
||||
{mission.leantimeProjectId && mission.leantimeProjectId.toString().trim() !== '' && (() => {
|
||||
{(() => {
|
||||
const isValid = (value: any): boolean => {
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed !== '' && trimmed !== '0' && trimmed !== 'null' && trimmed !== 'undefined';
|
||||
}
|
||||
if (typeof value === 'number') return value !== 0;
|
||||
return true;
|
||||
};
|
||||
return isValid(mission.leantimeProjectId);
|
||||
})() && (() => {
|
||||
// Build Leantime URL: agilite.slm-lab.net/projects/showProject/[projectId]
|
||||
// If it's already a full URL, use it; otherwise build from ID
|
||||
const leantimeUrl = mission.leantimeProjectId.startsWith('http')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user