jiraCloud/lib/requestTypeFields.js
jmcqueen 225ca27c99 Render compact approval details in Adaptive Card FactSets.
Use a two-column FactSet for short fields and keep multi-line textarea values in separate blocks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-28 12:45:14 -04:00

131 lines
4.3 KiB
JavaScript

import fs from 'fs';
import { formatJiraRichText } from './jiraRichText.js';
const SKIP_FIELD_IDS = new Set(['attachment']);
export function loadRequestTypeFields() {
const path = './config/requestTypeFields.json';
if (!fs.existsSync(path)) {
return { common: { displayFields: [] }, groups: {}, requestTypes: {} };
}
return JSON.parse(fs.readFileSync(path, 'utf8'));
}
function resolveFieldEntry(entry, groups) {
if (typeof entry === 'string' && groups[entry]) {
return groups[entry].displayFields || [];
}
return [entry];
}
export function getDisplayFieldsForRequestType(requestTypeId, fieldMap = loadRequestTypeFields()) {
const key = String(requestTypeId);
const typeConfig = fieldMap.requestTypes?.[key];
if (!typeConfig) {
return fieldMap.common?.displayFields || [];
}
const groups = fieldMap.groups || {};
const resolved = [];
if (typeConfig.includeCommon !== false) {
resolved.push(...(fieldMap.common?.displayFields || []));
}
for (const groupRef of typeConfig.groups || []) {
const groupFields = groups[groupRef]?.displayFields || [];
resolved.push(...groupFields);
}
for (const field of typeConfig.displayFields || []) {
resolved.push(...resolveFieldEntry(field, groups));
}
const seen = new Set();
return resolved.filter(field => {
const dedupeKey = field.path || field.fieldId;
if (!dedupeKey || seen.has(dedupeKey) || SKIP_FIELD_IDS.has(field.fieldId)) {
return false;
}
seen.add(dedupeKey);
return true;
});
}
export function formatFieldValue(value, format) {
if (value == null || value === '') {
return null;
}
switch (format) {
case 'option':
return value.value ?? value.name ?? String(value);
case 'user':
return value.displayName ?? value.emailAddress ?? String(value);
case 'users':
if (!Array.isArray(value)) {
return formatFieldValue(value, 'user');
}
return value.map(item => formatFieldValue(item, 'user')).filter(Boolean).join(', ');
case 'datetime':
case 'date':
return new Date(value).toLocaleString();
case 'cmdb':
if (Array.isArray(value)) {
return value.map(item => item.label || item.name || item.objectKey || item.value).filter(Boolean).join(', ');
}
return value.label || value.name || value.objectKey || String(value);
case 'multiselect':
case 'multicheckboxes':
if (!Array.isArray(value)) {
return String(value);
}
return value.map(item => item.value || item.label || String(item)).join(', ');
case 'cascading':
if (value.child) {
return `${value.value}${value.child.value}`;
}
return value.value ?? String(value);
case 'textarea':
case 'text':
default:
if (typeof value === 'object') {
const richText = formatJiraRichText(value);
return richText || value.displayName || value.value || value.name || null;
}
return formatJiraRichText(value) || null;
}
}
export function getFieldValueFromTicket(jiraTicket, fieldDef) {
if (fieldDef.path) {
return fieldDef.path.split('.').reduce((current, part) => current?.[part], jiraTicket);
}
const fieldId = fieldDef.fieldId;
if (!fieldId) {
return null;
}
if (fieldId === 'summary' || fieldId === 'description' || fieldId === 'priority' || fieldId === 'created' || fieldId === 'updated') {
const fields = jiraTicket.issue?.fields || {};
return fields[fieldId];
}
return jiraTicket.issue?.fields?.[fieldId] ?? null;
}
export function buildDetailLinesForRequestType(jiraTicket, requestTypeId, fieldMap = loadRequestTypeFields()) {
const fields = getDisplayFieldsForRequestType(requestTypeId, fieldMap);
const lines = [];
for (const fieldDef of fields) {
const rawValue = getFieldValueFromTicket(jiraTicket, fieldDef);
const formatted = formatFieldValue(rawValue, fieldDef.format);
if (formatted) {
lines.push({ label: fieldDef.label, value: formatted, format: fieldDef.format });
}
}
return lines;
}