nodes/YouTrack/resources/command/shared.ts (54 lines of code) (raw):
import type { INodeProperties } from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';
import type { CommandSharedRequestBody } from '../types';
export const commandSharedDescription: INodeProperties[] = [
// Command: Issue IDs parameter
{
displayName: 'Issue IDs',
name: 'issueIds',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['command'],
operation: ['execute'],
},
},
default: '',
placeholder: 'e.g. PROJECT-123, PROJECT-124, 2-15',
description:
'Comma-separated list of issue IDs for bulk operations. Examples: "PROJECT-123, PROJECT-124" (readable IDs) or "2-15, 2-16" (database IDs). Supports mixing both formats. The command will be applied to all listed issues.',
routing: {
send: {
type: 'body',
property: 'issues',
preSend: [
/**
* Parses and validates comma-separated issue IDs.
* Automatically detects format: database ID (e.g., "2-15") vs readable ID (e.g., "PROJECT-123").
* Database IDs match the pattern "number-number" and are sent as { id: "..." }.
* Readable IDs are sent as { idReadable: "..." }.
*
* @throws {NodeOperationError} If no issue IDs are provided
*/
async function (this, requestOptions) {
const issueIds = this.getNodeParameter('issueIds') as string;
if (!issueIds) {
throw new NodeOperationError(
this.getNode(),
'Issue IDs are required',
{ itemIndex: this.getItemIndex() }
);
}
// Split by comma and trim
const ids = issueIds
.split(',')
.map((id) => id.trim())
.filter((id) => id.length > 0);
// Convert to array of issue objects
const issues = ids.map((id) => {
// Check if it's a database ID (format: number-number)
const isDatabaseId = /^\d+-\d+$/.test(id);
if (isDatabaseId) {
return { id };
}
// Otherwise, treat as readable ID
return { idReadable: id };
});
if (requestOptions.body && typeof requestOptions.body === 'object') {
(requestOptions.body as CommandSharedRequestBody).issues = issues;
}
return requestOptions;
},
],
},
},
},
];