Improve Webex approval card layout and remove duplicate fields.
Split the card header into separate blocks for readability and keep reporter only in the footer instead of details. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c6d3b9b531
commit
d0e1e20843
3 changed files with 110 additions and 47 deletions
|
|
@ -20,7 +20,6 @@
|
||||||
{ "path": "transition.to_status", "label": "To status" },
|
{ "path": "transition.to_status", "label": "To status" },
|
||||||
{ "path": "user.displayName", "label": "Moved by" },
|
{ "path": "user.displayName", "label": "Moved by" },
|
||||||
{ "fieldId": "priority", "label": "Priority", "format": "option" },
|
{ "fieldId": "priority", "label": "Priority", "format": "option" },
|
||||||
{ "fieldId": "reporter", "label": "Reporter", "format": "user" },
|
|
||||||
{ "fieldId": "assignee", "label": "Assignee", "format": "user" },
|
{ "fieldId": "assignee", "label": "Assignee", "format": "user" },
|
||||||
{ "fieldId": "created", "label": "Created", "format": "datetime" },
|
{ "fieldId": "created", "label": "Created", "format": "datetime" },
|
||||||
{ "fieldId": "updated", "label": "Updated", "format": "datetime" }
|
{ "fieldId": "updated", "label": "Updated", "format": "datetime" }
|
||||||
|
|
@ -68,7 +67,6 @@
|
||||||
"summaryOnly": {
|
"summaryOnly": {
|
||||||
"description": "Forms where JSM API only exposes summary — show summary + description",
|
"description": "Forms where JSM API only exposes summary — show summary + description",
|
||||||
"displayFields": [
|
"displayFields": [
|
||||||
{ "fieldId": "summary", "label": "Summary" },
|
|
||||||
{ "fieldId": "description", "label": "Description", "format": "textarea" }
|
{ "fieldId": "description", "label": "Description", "format": "textarea" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +285,6 @@
|
||||||
{ "fieldId": "customfield_10335", "label": "Reason for request", "format": "textarea" },
|
{ "fieldId": "customfield_10335", "label": "Reason for request", "format": "textarea" },
|
||||||
{ "fieldId": "customfield_10307", "label": "Implementation date", "format": "datetime" },
|
{ "fieldId": "customfield_10307", "label": "Implementation date", "format": "datetime" },
|
||||||
{ "fieldId": "customfield_10337", "label": "Reason for implementation date", "format": "textarea" },
|
{ "fieldId": "customfield_10337", "label": "Reason for implementation date", "format": "textarea" },
|
||||||
{ "fieldId": "summary", "label": "Summary" },
|
|
||||||
{ "fieldId": "description", "label": "Detailed description", "format": "textarea" }
|
{ "fieldId": "description", "label": "Detailed description", "format": "textarea" }
|
||||||
],
|
],
|
||||||
"notes": "Replaces retired request type 382. Transitions 81/101 inherited from 382 config — verify on first webhook."
|
"notes": "Replaces retired request type 382. Transitions 81/101 inherited from 382 config — verify on first webhook."
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { buildDetailLinesForRequestType } from '../lib/requestTypeFields.js';
|
import { buildDetailLinesForRequestType } from '../lib/requestTypeFields.js';
|
||||||
|
|
||||||
|
const PORTAL_BASE_URL = 'https://aeo.atlassian.net/servicedesk/customer/portal/135';
|
||||||
|
|
||||||
function appendDetailLines(detailText, lines) {
|
function appendDetailLines(detailText, lines) {
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
detailText += ` - **${line.label}:** ${line.value}\n`;
|
detailText += ` - **${line.label}:** ${line.value}\n`;
|
||||||
|
|
@ -11,20 +13,104 @@ function getRequestTypeId(jiraTicket) {
|
||||||
return jiraTicket.issue.fields?.customfield_10010?.requestType?.id;
|
return jiraTicket.issue.fields?.customfield_10010?.requestType?.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildCardPayload({ jiraTicket, cardText, detailText, assignmentText = '' }) {
|
function getRequestTypeLabel(jiraTicket) {
|
||||||
|
const requestTypeField = jiraTicket.issue.fields?.customfield_10010;
|
||||||
|
if (!requestTypeField) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return requestTypeField.errorMessage || requestTypeField.requestType?.name || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHeaderBlocks(jiraTicket) {
|
||||||
|
const issueKey = jiraTicket.issue.key;
|
||||||
|
const blocks = [
|
||||||
|
{
|
||||||
|
type: 'TextBlock',
|
||||||
|
text: `[${issueKey}](${PORTAL_BASE_URL}/${issueKey})`,
|
||||||
|
wrap: true,
|
||||||
|
weight: 'Bolder',
|
||||||
|
size: 'Medium',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'TextBlock',
|
||||||
|
text: jiraTicket.issue.fields.status.name,
|
||||||
|
wrap: true,
|
||||||
|
isSubtle: true,
|
||||||
|
spacing: 'None',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const requestTypeLabel = getRequestTypeLabel(jiraTicket);
|
||||||
|
if (requestTypeLabel) {
|
||||||
|
blocks.push({
|
||||||
|
type: 'TextBlock',
|
||||||
|
text: `**Request Type:** ${requestTypeLabel}`,
|
||||||
|
wrap: true,
|
||||||
|
spacing: 'Medium',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jiraTicket.issue.fields.summary) {
|
||||||
|
blocks.push({
|
||||||
|
type: 'TextBlock',
|
||||||
|
text: `**Summary:** ${jiraTicket.issue.fields.summary}`,
|
||||||
|
wrap: true,
|
||||||
|
spacing: 'Small',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPlainTextHeader(jiraTicket) {
|
||||||
|
const issueKey = jiraTicket.issue.key;
|
||||||
|
let text = `[${issueKey}](${PORTAL_BASE_URL}/${issueKey})\n`;
|
||||||
|
text += `${jiraTicket.issue.fields.status.name}\n`;
|
||||||
|
|
||||||
|
const requestTypeLabel = getRequestTypeLabel(jiraTicket);
|
||||||
|
if (requestTypeLabel) {
|
||||||
|
text += `\n**Request Type:** ${requestTypeLabel}\n`;
|
||||||
|
}
|
||||||
|
if (jiraTicket.issue.fields.summary) {
|
||||||
|
text += `**Summary:** ${jiraTicket.issue.fields.summary}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCardPayload({ jiraTicket, detailText, assignmentText = '' }) {
|
||||||
|
const body = [...buildHeaderBlocks(jiraTicket)];
|
||||||
|
|
||||||
|
if (detailText.trim()) {
|
||||||
|
body.push({
|
||||||
|
type: 'TextBlock',
|
||||||
|
wrap: true,
|
||||||
|
text: detailText.trim(),
|
||||||
|
separator: true,
|
||||||
|
spacing: 'Medium',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignmentText.trim()) {
|
||||||
|
body.push({
|
||||||
|
type: 'TextBlock',
|
||||||
|
text: assignmentText.trim(),
|
||||||
|
wrap: true,
|
||||||
|
separator: true,
|
||||||
|
spacing: 'Medium',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const requestCard = {
|
const requestCard = {
|
||||||
type: 'AdaptiveCard',
|
type: 'AdaptiveCard',
|
||||||
$schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
|
$schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
|
||||||
version: '1.2',
|
version: '1.2',
|
||||||
body: [
|
body,
|
||||||
{ type: 'TextBlock', text: cardText.trim(), wrap: true },
|
|
||||||
{ type: 'TextBlock', wrap: true, text: detailText.trim(), separator: true },
|
|
||||||
],
|
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'Action.OpenUrl',
|
type: 'Action.OpenUrl',
|
||||||
title: 'Open Request',
|
title: 'Open Request',
|
||||||
url: `https://aeo.atlassian.net/servicedesk/customer/portal/135/${jiraTicket.issue.key}`,
|
url: `${PORTAL_BASE_URL}/${jiraTicket.issue.key}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Action.Submit',
|
type: 'Action.Submit',
|
||||||
|
|
@ -35,17 +121,10 @@ function buildCardPayload({ jiraTicket, cardText, detailText, assignmentText = '
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (assignmentText.trim()) {
|
let requestText = buildPlainTextHeader(jiraTicket);
|
||||||
requestCard.body.push({
|
if (detailText.trim()) {
|
||||||
type: 'TextBlock',
|
requestText += `---\n${detailText}`;
|
||||||
text: assignmentText.trim(),
|
|
||||||
wrap: true,
|
|
||||||
separator: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let requestText = cardText;
|
|
||||||
requestText += `---\n${detailText}`;
|
|
||||||
if (assignmentText.trim()) {
|
if (assignmentText.trim()) {
|
||||||
requestText += `---\n${assignmentText}`;
|
requestText += `---\n${assignmentText}`;
|
||||||
}
|
}
|
||||||
|
|
@ -55,18 +134,6 @@ function buildCardPayload({ jiraTicket, cardText, detailText, assignmentText = '
|
||||||
|
|
||||||
export function buildChangeApproval(jiraTicket, log) {
|
export function buildChangeApproval(jiraTicket, log) {
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
let cardText = '';
|
|
||||||
cardText += `[${jiraTicket.issue.key}](https://aeo.atlassian.net/servicedesk/customer/portal/135/${jiraTicket.issue.key}) - ${jiraTicket.issue.fields.status.name}\n`;
|
|
||||||
|
|
||||||
if (jiraTicket.issue.fields.customfield_10010) {
|
|
||||||
if (jiraTicket.issue.fields.customfield_10010.errorMessage) {
|
|
||||||
cardText += `**Request Type:** ${jiraTicket.issue.fields.customfield_10010.errorMessage}\n`;
|
|
||||||
} else {
|
|
||||||
cardText += `**Request Type:** ${jiraTicket.issue.fields.customfield_10010.requestType.name}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cardText += `**Summary:** ${jiraTicket.issue.fields.summary}\n`;
|
|
||||||
|
|
||||||
let detailText = '**Details:**\n';
|
let detailText = '**Details:**\n';
|
||||||
if (jiraTicket.issue.fields.description) {
|
if (jiraTicket.issue.fields.description) {
|
||||||
detailText += `**Description:** ${jiraTicket.issue.fields.description}\n`;
|
detailText += `**Description:** ${jiraTicket.issue.fields.description}\n`;
|
||||||
|
|
@ -87,25 +154,17 @@ export function buildChangeApproval(jiraTicket, log) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasDetails = detailText.replace('**Details:**\n', '').trim().length > 0;
|
||||||
log.logDebug('buildChangeApproval', `Built card for ${jiraTicket.issue.key}`);
|
log.logDebug('buildChangeApproval', `Built card for ${jiraTicket.issue.key}`);
|
||||||
resolve(buildCardPayload({ jiraTicket, cardText, detailText }));
|
resolve(buildCardPayload({
|
||||||
|
jiraTicket,
|
||||||
|
detailText: hasDetails ? detailText : '',
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildRequestApproval(jiraTicket) {
|
export function buildRequestApproval(jiraTicket) {
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
let cardText = '';
|
|
||||||
cardText += `[${jiraTicket.issue.key}](https://aeo.atlassian.net/servicedesk/customer/portal/135/${jiraTicket.issue.key}) - ${jiraTicket.issue.fields.status.name}\n`;
|
|
||||||
|
|
||||||
if (jiraTicket.issue.fields.customfield_10010) {
|
|
||||||
if (jiraTicket.issue.fields.customfield_10010.errorMessage) {
|
|
||||||
cardText += `**Request Type:** ${jiraTicket.issue.fields.customfield_10010.errorMessage}\n`;
|
|
||||||
} else {
|
|
||||||
cardText += `**Request Type:** ${jiraTicket.issue.fields.customfield_10010.requestType.name}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cardText += `**Summary:** ${jiraTicket.issue.fields.summary}\n`;
|
|
||||||
|
|
||||||
let detailText = '**Details:**\n';
|
let detailText = '**Details:**\n';
|
||||||
const requestTypeId = getRequestTypeId(jiraTicket);
|
const requestTypeId = getRequestTypeId(jiraTicket);
|
||||||
if (requestTypeId) {
|
if (requestTypeId) {
|
||||||
|
|
@ -117,11 +176,17 @@ export function buildRequestApproval(jiraTicket) {
|
||||||
if (jiraTicket.issue.fields.customfield_10318) { detailText += ` - **Position:** ${jiraTicket.issue.fields.customfield_10318}\n`; }
|
if (jiraTicket.issue.fields.customfield_10318) { detailText += ` - **Position:** ${jiraTicket.issue.fields.customfield_10318}\n`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasDetails = detailText.replace('**Details:**\n', '').trim().length > 0;
|
||||||
|
|
||||||
let assignmentText = '';
|
let assignmentText = '';
|
||||||
if (jiraTicket.issue.fields.reporter) {
|
if (jiraTicket.issue.fields.reporter) {
|
||||||
assignmentText += `**Reporter:** ${jiraTicket.issue.fields.reporter.displayName}\n`;
|
assignmentText += `**Reporter:** ${jiraTicket.issue.fields.reporter.displayName}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(buildCardPayload({ jiraTicket, cardText, detailText, assignmentText }));
|
resolve(buildCardPayload({
|
||||||
|
jiraTicket,
|
||||||
|
detailText: hasDetails ? detailText : '',
|
||||||
|
assignmentText,
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ describe('getDisplayFieldsForRequestType', () => {
|
||||||
it('returns fields for Application Access including common and groups', () => {
|
it('returns fields for Application Access including common and groups', () => {
|
||||||
const fields = getDisplayFieldsForRequestType('209');
|
const fields = getDisplayFieldsForRequestType('209');
|
||||||
const labels = fields.map(f => f.label);
|
const labels = fields.map(f => f.label);
|
||||||
assert.ok(labels.includes('Reporter'));
|
assert.ok(!labels.includes('Reporter'));
|
||||||
assert.ok(labels.includes('First name'));
|
assert.ok(labels.includes('First name'));
|
||||||
assert.ok(labels.includes('IT'));
|
assert.ok(labels.includes('IT'));
|
||||||
});
|
});
|
||||||
|
|
@ -46,7 +46,8 @@ describe('getDisplayFieldsForRequestType', () => {
|
||||||
it('uses summaryOnly for legacy single-field forms', () => {
|
it('uses summaryOnly for legacy single-field forms', () => {
|
||||||
const fields = getDisplayFieldsForRequestType('211');
|
const fields = getDisplayFieldsForRequestType('211');
|
||||||
const labels = fields.map(f => f.label);
|
const labels = fields.map(f => f.label);
|
||||||
assert.ok(labels.includes('Summary'));
|
assert.ok(labels.includes('Description'));
|
||||||
|
assert.ok(!labels.includes('Summary'));
|
||||||
assert.ok(!labels.includes('First name'));
|
assert.ok(!labels.includes('First name'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue