66 lines
2.2 KiB
TypeScript
66 lines
2.2 KiB
TypeScript
const MAX_REQUEST_LABEL_CHARACTERS = 48;
|
|
const MIN_RUN_ID_PREFIX_CHARACTERS = 8;
|
|
|
|
export interface LabelledRun {
|
|
runId: string;
|
|
featureName?: string;
|
|
request?: string;
|
|
}
|
|
|
|
function requestRunLabel(request: string) {
|
|
const normalized = request.trim().replace(/\s+/g, " ");
|
|
const characters = [...normalized];
|
|
if (characters.length <= MAX_REQUEST_LABEL_CHARACTERS) return normalized;
|
|
const keptCharacters = characters.slice(0, MAX_REQUEST_LABEL_CHARACTERS - 1);
|
|
const candidate = keptCharacters.join("");
|
|
const nextCharacter = characters[MAX_REQUEST_LABEL_CHARACTERS - 1];
|
|
const lastWhitespace = candidate.search(/\s+\S*$/);
|
|
const bounded =
|
|
nextCharacter !== undefined && /\s/.test(nextCharacter)
|
|
? candidate.trimEnd()
|
|
: lastWhitespace > 0
|
|
? candidate.slice(0, lastWhitespace).trimEnd()
|
|
: candidate;
|
|
return `${bounded}…`;
|
|
}
|
|
|
|
export function deriveRunLabel(run: LabelledRun) {
|
|
const featureName = run.featureName?.trim();
|
|
if (featureName) return featureName;
|
|
const request = run.request?.trim();
|
|
return request ? requestRunLabel(request) : run.runId;
|
|
}
|
|
|
|
function uniqueRunIdPrefix(runId: string, peers: string[]) {
|
|
const characters = [...runId];
|
|
for (
|
|
let length = Math.min(MIN_RUN_ID_PREFIX_CHARACTERS, characters.length);
|
|
length < characters.length;
|
|
length++
|
|
) {
|
|
const prefix = characters.slice(0, length).join("");
|
|
if (peers.every((peer) => !peer.startsWith(prefix))) return prefix;
|
|
}
|
|
return runId;
|
|
}
|
|
|
|
/** Derives presentation labels and disambiguates only collisions in this list. */
|
|
export function deriveRunLabels<T extends LabelledRun>(runs: readonly T[]) {
|
|
const baseLabels = runs.map(deriveRunLabel);
|
|
const collisions = new Map<string, number[]>();
|
|
for (const [index, label] of baseLabels.entries()) {
|
|
const indexes = collisions.get(label) ?? [];
|
|
indexes.push(index);
|
|
collisions.set(label, indexes);
|
|
}
|
|
return baseLabels.map((label, index) => {
|
|
const indexes = collisions.get(label)!;
|
|
if (indexes.length === 1) return label;
|
|
const run = runs[index]!;
|
|
const peers = indexes
|
|
.filter((peerIndex) => peerIndex !== index)
|
|
.map((peerIndex) => runs[peerIndex]!.runId);
|
|
return `${label} · ${uniqueRunIdPrefix(run.runId, peers)}`;
|
|
});
|
|
}
|