65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
import type { JiraIssue } from '../types/jira'
|
|
import { buildIssueIdToKeyMap, resolveParentIssueKey } from './parentResolve'
|
|
|
|
/** ID du champ Story Points (souvent `customfield_10028` — à vérifier dans Jira). */
|
|
export function getStoryPointsFieldId(): string {
|
|
return import.meta.env.VITE_JIRA_STORY_POINTS_FIELD?.trim() || 'customfield_10028'
|
|
}
|
|
|
|
function coerceNumber(v: unknown): number | null {
|
|
if (v == null || v === '') return null
|
|
if (typeof v === 'number' && Number.isFinite(v)) return v
|
|
if (typeof v === 'string') {
|
|
const n = Number(v)
|
|
return Number.isFinite(n) ? n : null
|
|
}
|
|
if (typeof v === 'object' && v !== null && 'value' in v) {
|
|
return coerceNumber((v as { value: unknown }).value)
|
|
}
|
|
return null
|
|
}
|
|
|
|
/** Story Points bruts depuis le champ custom Jira (nombre, chaîne, ou `{ value }`). */
|
|
export function getStoryPoints(issue: JiraIssue): number {
|
|
const id = getStoryPointsFieldId()
|
|
const raw = (issue.fields as Record<string, unknown>)[id]
|
|
const n = coerceNumber(raw)
|
|
return n ?? 0
|
|
}
|
|
|
|
/**
|
|
* Reste « en unités » comme dans ton export : secondes / 27 000
|
|
* (27 000 s ≈ 7,5 h — une journée-type Atlassian).
|
|
*/
|
|
export function getRemainingEstimateUnits(issue: JiraIssue): number {
|
|
const sec = issue.fields.timetracking?.remainingEstimateSeconds
|
|
if (sec == null || !Number.isFinite(sec)) return 0
|
|
const v = sec / 27000
|
|
return Number.isFinite(v) ? v : 0
|
|
}
|
|
|
|
/** Objet plat proche de ton ancien `issues.map` + clé parent résolue pour le debug. */
|
|
export function toTicketRow(issue: JiraIssue, allIssues: JiraIssue[]): {
|
|
key: string
|
|
summary: string
|
|
sp: number
|
|
remaining: number
|
|
status: string
|
|
issuetype: string
|
|
assignee: string
|
|
parentKey?: string
|
|
} {
|
|
const idToKey = buildIssueIdToKeyMap(allIssues)
|
|
const parentKey = resolveParentIssueKey(issue, idToKey)
|
|
return {
|
|
key: issue.key,
|
|
summary: issue.fields.summary,
|
|
sp: getStoryPoints(issue),
|
|
remaining: getRemainingEstimateUnits(issue),
|
|
status: issue.fields.status?.name ?? 'Inconnu',
|
|
issuetype: issue.fields.issuetype?.name ?? 'Inconnu',
|
|
assignee: issue.fields.assignee?.displayName ?? 'Inconnu',
|
|
...(parentKey ? { parentKey } : {}),
|
|
}
|
|
}
|