mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-23 18:41:48 -08:00
feat(Jira Node): Add Simplify Output option to Issue > Get (#2408)
* ✨ Add option to use Jira field display names * 🚸 Make mapped fields more deterministic * ♻️ Refactor Jira user loadOptions * Moved and renamed the option as well as only returning the fields to * Tweaked Friendly Fields to make it "Simplify Output" following similar patterns to other nodes * ⚡ Improvements Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
This commit is contained in:
parent
5ba4c27d8c
commit
016aeaaa79
|
@ -12,6 +12,7 @@ import {
|
|||
import {
|
||||
ICredentialDataDecryptedObject,
|
||||
IDataObject,
|
||||
JsonObject,
|
||||
NodeApiError,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
@ -69,7 +70,7 @@ export async function jiraSoftwareCloudApiRequest(this: IHookFunctions | IExecut
|
|||
try {
|
||||
return await this.helpers.request!(options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,6 +120,49 @@ export function getId(url: string) {
|
|||
return url.split('/').pop();
|
||||
}
|
||||
|
||||
export function simplifyIssueOutput(responseData: {
|
||||
names: { [key: string]: string },
|
||||
fields: IDataObject,
|
||||
id: string,
|
||||
key: string,
|
||||
self: string
|
||||
}) {
|
||||
const mappedFields: IDataObject = {
|
||||
id: responseData.id,
|
||||
key: responseData.key,
|
||||
self: responseData.self,
|
||||
};
|
||||
// Sort custom fields last so we map them last
|
||||
const customField = /^customfield_\d+$/;
|
||||
const sortedFields: string[] = Object.keys(responseData.fields).sort((a, b) => {
|
||||
if (customField.test(a) && customField.test(b)) {
|
||||
return a > b ? 1 : -1;
|
||||
}
|
||||
if (customField.test(a)) {
|
||||
return 1;
|
||||
}
|
||||
if (customField.test(b)) {
|
||||
return -1;
|
||||
}
|
||||
return a > b ? 1 : -1;
|
||||
});
|
||||
for (const field of sortedFields) {
|
||||
if (responseData.names[field] in mappedFields) {
|
||||
let newField: string = responseData.names[field];
|
||||
let counter = 0;
|
||||
while (newField in mappedFields) {
|
||||
counter++;
|
||||
newField = `${responseData.names[field]}_${counter}`;
|
||||
}
|
||||
mappedFields[newField] = responseData.fields[field];
|
||||
} else {
|
||||
mappedFields[responseData.names[field] || field] = responseData.fields[field];
|
||||
}
|
||||
}
|
||||
|
||||
return mappedFields;
|
||||
}
|
||||
|
||||
export const allEvents = [
|
||||
'board_created',
|
||||
'board_updated',
|
||||
|
|
|
@ -530,6 +530,24 @@ export const issueFields: INodeProperties[] = [
|
|||
default: '',
|
||||
description: 'Issue Key',
|
||||
},
|
||||
{
|
||||
displayName: 'Simplify Output',
|
||||
name: 'simplifyOutput',
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'issue',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: `Return a simplified output of the issues fields.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
|
|
|
@ -18,12 +18,14 @@ import {
|
|||
INodePropertyOptions,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
JsonObject,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
jiraSoftwareCloudApiRequest,
|
||||
jiraSoftwareCloudApiRequestAllItems,
|
||||
simplifyIssueOutput,
|
||||
validateJSON,
|
||||
} from './GenericFunctions';
|
||||
|
||||
|
@ -178,7 +180,7 @@ export class Jira implements INodeType {
|
|||
} catch (err) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: `Connection details not valid: ${err.message}`,
|
||||
message: `Connection details not valid: ${(err as JsonObject).message}`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
@ -303,45 +305,29 @@ export class Jira implements INodeType {
|
|||
// Get all the users to display them to user so that he can
|
||||
// select them easily
|
||||
async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const jiraVersion = this.getCurrentNodeParameter('jiraVersion') as string;
|
||||
const query: IDataObject = {};
|
||||
let endpoint = '/api/2/users/search';
|
||||
|
||||
if (jiraVersion === 'server') {
|
||||
// the interface call must bring username
|
||||
const users = await jiraSoftwareCloudApiRequest.call(this, '/api/2/user/search', 'GET', {},
|
||||
{
|
||||
username: '\'',
|
||||
},
|
||||
);
|
||||
for (const user of users) {
|
||||
const userName = user.displayName;
|
||||
const userId = user.name;
|
||||
|
||||
returnData.push({
|
||||
name: userName,
|
||||
value: userId,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const users = await jiraSoftwareCloudApiRequest.call(this, '/api/2/users/search', 'GET');
|
||||
|
||||
for (const user of users) {
|
||||
const userName = user.displayName;
|
||||
const userId = user.accountId;
|
||||
|
||||
returnData.push({
|
||||
name: userName,
|
||||
value: userId,
|
||||
});
|
||||
}
|
||||
endpoint = '/api/2/user/search';
|
||||
query.username = '\'';
|
||||
}
|
||||
|
||||
returnData.sort((a, b) => {
|
||||
if (a.name < b.name) { return -1; }
|
||||
if (a.name > b.name) { return 1; }
|
||||
return 0;
|
||||
const users = await jiraSoftwareCloudApiRequest.call(this, endpoint, 'GET', {}, query);
|
||||
|
||||
return users.reduce((activeUsers: INodePropertyOptions[], user: IDataObject) => {
|
||||
if (user.active) {
|
||||
activeUsers.push({
|
||||
name: user.displayName as string,
|
||||
value: (user.accountId || user.name) as string,
|
||||
});
|
||||
}
|
||||
return activeUsers;
|
||||
}, []).sort((a: INodePropertyOptions, b: INodePropertyOptions) => {
|
||||
return a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1;
|
||||
});
|
||||
|
||||
return returnData;
|
||||
},
|
||||
|
||||
// Get all the groups to display them to user so that he can
|
||||
|
@ -418,10 +404,10 @@ export class Jira implements INodeType {
|
|||
for (const key of Object.keys(fields)) {
|
||||
const field = fields[key];
|
||||
if (field.schema && Object.keys(field.schema).includes('customId')) {
|
||||
returnData.push({
|
||||
name: field.name,
|
||||
value: field.key || field.fieldId,
|
||||
});
|
||||
returnData.push({
|
||||
name: field.name,
|
||||
value: field.key || field.fieldId,
|
||||
});
|
||||
}
|
||||
}
|
||||
return returnData;
|
||||
|
@ -642,6 +628,7 @@ export class Jira implements INodeType {
|
|||
if (operation === 'get') {
|
||||
for (let i = 0; i < length; i++) {
|
||||
const issueKey = this.getNodeParameter('issueKey', i) as string;
|
||||
const simplifyOutput = this.getNodeParameter('simplifyOutput', i) as boolean;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
if (additionalFields.fields) {
|
||||
qs.fields = additionalFields.fields as string;
|
||||
|
@ -652,6 +639,9 @@ export class Jira implements INodeType {
|
|||
if (additionalFields.expand) {
|
||||
qs.expand = additionalFields.expand as string;
|
||||
}
|
||||
if (simplifyOutput) {
|
||||
qs.expand = `${qs.expand || ''},names`;
|
||||
}
|
||||
if (additionalFields.properties) {
|
||||
qs.properties = additionalFields.properties as string;
|
||||
}
|
||||
|
@ -659,7 +649,12 @@ export class Jira implements INodeType {
|
|||
qs.updateHistory = additionalFields.updateHistory as string;
|
||||
}
|
||||
responseData = await jiraSoftwareCloudApiRequest.call(this, `/api/2/issue/${issueKey}`, 'GET', {}, qs);
|
||||
returnData.push(responseData);
|
||||
|
||||
if (simplifyOutput) {
|
||||
returnData.push(simplifyIssueOutput(responseData));
|
||||
} else {
|
||||
returnData.push(responseData);
|
||||
}
|
||||
}
|
||||
}
|
||||
//https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-search-post
|
||||
|
@ -689,7 +684,7 @@ export class Jira implements INodeType {
|
|||
responseData = await jiraSoftwareCloudApiRequest.call(this, `/api/2/search`, 'POST', body);
|
||||
responseData = responseData.issues;
|
||||
}
|
||||
returnData.push.apply(returnData, responseData);
|
||||
returnData.push(...responseData);
|
||||
}
|
||||
}
|
||||
//https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-rest-api-2-issue-issueIdOrKey-changelog-get
|
||||
|
|
Loading…
Reference in a new issue