From fc40b4f7af72fdf3c096386857ef6a4dd0b58af5 Mon Sep 17 00:00:00 2001 From: Adam Gough <77861281+aadamgough@users.noreply.github.com> Date: Thu, 18 Dec 2025 17:56:10 -0800 Subject: [PATCH] fix(tools): improved slack output ux and jira params (#2462) * fixed slack output * updated jira * removed comment * change team uuid --- apps/docs/content/docs/en/tools/jira.mdx | 35 ++- apps/sim/app/api/tools/jira/write/route.ts | 93 +++++++- .../components/tag-dropdown/tag-dropdown.tsx | 38 ++- apps/sim/blocks/blocks/jira.ts | 140 +++++++++++ apps/sim/tools/jira/get_users.ts | 217 ++++++++++++++++++ apps/sim/tools/jira/index.ts | 2 + apps/sim/tools/jira/types.ts | 6 + apps/sim/tools/jira/write.ts | 51 +++- apps/sim/tools/registry.ts | 2 + apps/sim/tools/slack/list_channels.ts | 13 ++ apps/sim/tools/slack/list_users.ts | 13 ++ apps/sim/tools/slack/types.ts | 4 + 12 files changed, 578 insertions(+), 36 deletions(-) create mode 100644 apps/sim/tools/jira/get_users.ts diff --git a/apps/docs/content/docs/en/tools/jira.mdx b/apps/docs/content/docs/en/tools/jira.mdx index ddd28524c..7018f79b6 100644 --- a/apps/docs/content/docs/en/tools/jira.mdx +++ b/apps/docs/content/docs/en/tools/jira.mdx @@ -97,10 +97,16 @@ Write a Jira issue | `projectId` | string | Yes | Project ID for the issue | | `summary` | string | Yes | Summary for the issue | | `description` | string | No | Description for the issue | -| `priority` | string | No | Priority for the issue | -| `assignee` | string | No | Assignee for the issue | +| `priority` | string | No | Priority ID or name for the issue \(e.g., "10000" or "High"\) | +| `assignee` | string | No | Assignee account ID for the issue | | `cloudId` | string | No | Jira Cloud ID for the instance. If not provided, it will be fetched using the domain. | | `issueType` | string | Yes | Type of issue to create \(e.g., Task, Story\) | +| `labels` | array | No | Labels for the issue \(array of label names\) | +| `duedate` | string | No | Due date for the issue \(format: YYYY-MM-DD\) | +| `reporter` | string | No | Reporter account ID for the issue | +| `environment` | string | No | Environment information for the issue | +| `customFieldId` | string | No | Custom field ID \(e.g., customfield_10001\) | +| `customFieldValue` | string | No | Value for the custom field | #### Output @@ -110,6 +116,7 @@ Write a Jira issue | `issueKey` | string | Created issue key \(e.g., PROJ-123\) | | `summary` | string | Issue summary | | `url` | string | URL to the created issue | +| `assigneeId` | string | Account ID of the assigned user \(if assigned\) | ### `jira_bulk_read` @@ -523,6 +530,30 @@ Remove a watcher from a Jira issue | `issueKey` | string | Issue key | | `watcherAccountId` | string | Removed watcher account ID | +### `jira_get_users` + +Get Jira users. If an account ID is provided, returns a single user. Otherwise, returns a list of all users. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) | +| `accountId` | string | No | Optional account ID to get a specific user. If not provided, returns all users. | +| `startAt` | number | No | The index of the first user to return \(for pagination, default: 0\) | +| `maxResults` | number | No | Maximum number of users to return \(default: 50\) | +| `cloudId` | string | No | Jira Cloud ID for the instance. If not provided, it will be fetched using the domain. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `ts` | string | Timestamp of the operation | +| `users` | json | Array of users with accountId, displayName, emailAddress, active status, and avatarUrls | +| `total` | number | Total number of users returned | +| `startAt` | number | Pagination start index | +| `maxResults` | number | Maximum results per page | + ## Notes diff --git a/apps/sim/app/api/tools/jira/write/route.ts b/apps/sim/app/api/tools/jira/write/route.ts index 48b90da5e..0eb114892 100644 --- a/apps/sim/app/api/tools/jira/write/route.ts +++ b/apps/sim/app/api/tools/jira/write/route.ts @@ -20,6 +20,12 @@ export async function POST(request: Request) { cloudId: providedCloudId, issueType, parent, + labels, + duedate, + reporter, + environment, + customFieldId, + customFieldValue, } = await request.json() if (!domain) { @@ -94,17 +100,57 @@ export async function POST(request: Request) { } if (priority !== undefined && priority !== null && priority !== '') { - fields.priority = { - name: priority, + const isNumericId = /^\d+$/.test(priority) + fields.priority = isNumericId ? { id: priority } : { name: priority } + } + + if (labels !== undefined && labels !== null && Array.isArray(labels) && labels.length > 0) { + fields.labels = labels + } + + if (duedate !== undefined && duedate !== null && duedate !== '') { + fields.duedate = duedate + } + + if (reporter !== undefined && reporter !== null && reporter !== '') { + fields.reporter = { + id: reporter, } } - if (assignee !== undefined && assignee !== null && assignee !== '') { - fields.assignee = { - id: assignee, + if (environment !== undefined && environment !== null && environment !== '') { + fields.environment = { + type: 'doc', + version: 1, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: environment, + }, + ], + }, + ], } } + if ( + customFieldId !== undefined && + customFieldId !== null && + customFieldId !== '' && + customFieldValue !== undefined && + customFieldValue !== null && + customFieldValue !== '' + ) { + const fieldId = customFieldId.startsWith('customfield_') + ? customFieldId + : `customfield_${customFieldId}` + + fields[fieldId] = customFieldValue + } + const body = { fields } const response = await fetch(url, { @@ -132,16 +178,47 @@ export async function POST(request: Request) { } const responseData = await response.json() - logger.info('Successfully created Jira issue:', responseData.key) + const issueKey = responseData.key || 'unknown' + logger.info('Successfully created Jira issue:', issueKey) + + let assigneeId: string | undefined + if (assignee !== undefined && assignee !== null && assignee !== '') { + const assignUrl = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/issue/${issueKey}/assignee` + logger.info('Assigning issue to:', assignee) + + const assignResponse = await fetch(assignUrl, { + method: 'PUT', + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + accountId: assignee, + }), + }) + + if (!assignResponse.ok) { + const assignErrorText = await assignResponse.text() + logger.warn('Failed to assign issue (issue was created successfully):', { + status: assignResponse.status, + error: assignErrorText, + }) + } else { + assigneeId = assignee + logger.info('Successfully assigned issue to:', assignee) + } + } return NextResponse.json({ success: true, output: { ts: new Date().toISOString(), - issueKey: responseData.key || 'unknown', + issueKey: issueKey, summary: responseData.fields?.summary || 'Issue created', success: true, - url: `https://${domain}/browse/${responseData.key}`, + url: `https://${domain}/browse/${issueKey}`, + ...(assigneeId && { assigneeId }), }, }) } catch (error: any) { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx index dcdf3e638..ea37025f9 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx @@ -1214,31 +1214,25 @@ export const TagDropdown: React.FC = ({ let processedTag = tag - // Check if this is a file property and add [0] automatically - // Only include user-accessible fields (matches UserFile interface) - const fileProperties = ['id', 'name', 'url', 'size', 'type'] const parts = tag.split('.') - if (parts.length >= 2 && fileProperties.includes(parts[parts.length - 1])) { - const fieldName = parts[parts.length - 2] + if (parts.length >= 3 && blockGroup) { + const arrayFieldName = parts[1] // e.g., "channels", "files", "users" + const block = useWorkflowStore.getState().blocks[blockGroup.blockId] + const blockConfig = block ? (getBlock(block.type) ?? null) : null + const mergedSubBlocks = getMergedSubBlocks(blockGroup.blockId) - if (blockGroup) { - const block = useWorkflowStore.getState().blocks[blockGroup.blockId] - const blockConfig = block ? (getBlock(block.type) ?? null) : null - const mergedSubBlocks = getMergedSubBlocks(blockGroup.blockId) + const fieldType = getOutputTypeForPath( + block, + blockConfig, + blockGroup.blockId, + arrayFieldName, + mergedSubBlocks + ) - const fieldType = getOutputTypeForPath( - block, - blockConfig, - blockGroup.blockId, - fieldName, - mergedSubBlocks - ) - - if (fieldType === 'files') { - const blockAndField = parts.slice(0, -1).join('.') - const property = parts[parts.length - 1] - processedTag = `${blockAndField}[0].${property}` - } + if (fieldType === 'files' || fieldType === 'array') { + const blockName = parts[0] + const remainingPath = parts.slice(2).join('.') + processedTag = `${blockName}.${arrayFieldName}[0].${remainingPath}` } } diff --git a/apps/sim/blocks/blocks/jira.ts b/apps/sim/blocks/blocks/jira.ts index 98cd7166b..3e4347d1e 100644 --- a/apps/sim/blocks/blocks/jira.ts +++ b/apps/sim/blocks/blocks/jira.ts @@ -43,6 +43,7 @@ export const JiraBlock: BlockConfig = { { label: 'Delete Issue Link', id: 'delete_link' }, { label: 'Add Watcher', id: 'add_watcher' }, { label: 'Remove Watcher', id: 'remove_watcher' }, + { label: 'Get Users', id: 'get_users' }, ], value: () => 'read', }, @@ -194,6 +195,71 @@ export const JiraBlock: BlockConfig = { dependsOn: ['projectId'], condition: { field: 'operation', value: ['update', 'write'] }, }, + // Write Issue additional fields + { + id: 'assignee', + title: 'Assignee Account ID', + type: 'short-input', + placeholder: 'Assignee account ID (e.g., 5b109f2e9729b51b54dc274d)', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, + { + id: 'priority', + title: 'Priority', + type: 'short-input', + placeholder: 'Priority ID or name (e.g., "10000" or "High")', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, + { + id: 'labels', + title: 'Labels', + type: 'short-input', + placeholder: 'Comma-separated labels (e.g., bug, urgent)', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, + { + id: 'duedate', + title: 'Due Date', + type: 'short-input', + placeholder: 'YYYY-MM-DD (e.g., 2024-12-31)', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, + { + id: 'reporter', + title: 'Reporter Account ID', + type: 'short-input', + placeholder: 'Reporter account ID', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, + { + id: 'environment', + title: 'Environment', + type: 'long-input', + placeholder: 'Environment information (e.g., Production, Staging)', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, + { + id: 'customFieldId', + title: 'Custom Field ID', + type: 'short-input', + placeholder: 'e.g., customfield_10001 or 10001', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, + { + id: 'teamUuid', + title: 'Team UUID', + type: 'short-input', + placeholder: 'e.g., b3aa307a-76ea-462d-b6f1-a6e89ce9858a', + dependsOn: ['projectId'], + condition: { field: 'operation', value: 'write' }, + }, // Delete Issue fields { id: 'deleteSubtasks', @@ -351,6 +417,28 @@ export const JiraBlock: BlockConfig = { placeholder: 'Enter link ID to delete', condition: { field: 'operation', value: 'delete_link' }, }, + // Get Users fields + { + id: 'userAccountId', + title: 'Account ID', + type: 'short-input', + placeholder: 'Enter account ID for specific user', + condition: { field: 'operation', value: 'get_users' }, + }, + { + id: 'usersStartAt', + title: 'Start At', + type: 'short-input', + placeholder: 'Pagination start index (default: 0)', + condition: { field: 'operation', value: 'get_users' }, + }, + { + id: 'usersMaxResults', + title: 'Max Results', + type: 'short-input', + placeholder: 'Maximum users to return (default: 50)', + condition: { field: 'operation', value: 'get_users' }, + }, // Trigger SubBlocks ...getTrigger('jira_issue_created').subBlocks, ...getTrigger('jira_issue_updated').subBlocks, @@ -383,6 +471,7 @@ export const JiraBlock: BlockConfig = { 'jira_delete_issue_link', 'jira_add_watcher', 'jira_remove_watcher', + 'jira_get_users', ], config: { tool: (params) => { @@ -438,6 +527,8 @@ export const JiraBlock: BlockConfig = { return 'jira_add_watcher' case 'remove_watcher': return 'jira_remove_watcher' + case 'get_users': + return 'jira_get_users' default: return 'jira_retrieve' } @@ -461,12 +552,29 @@ export const JiraBlock: BlockConfig = { 'Project ID is required. Please select a project or enter a project ID manually.' ) } + // Parse comma-separated strings into arrays + const parseCommaSeparated = (value: string | undefined): string[] | undefined => { + if (!value || value.trim() === '') return undefined + return value + .split(',') + .map((item) => item.trim()) + .filter((item) => item !== '') + } + const writeParams = { projectId: effectiveProjectId, summary: params.summary || '', description: params.description || '', issueType: params.issueType || 'Task', parent: params.parentIssue ? { key: params.parentIssue } : undefined, + assignee: params.assignee || undefined, + priority: params.priority || undefined, + labels: parseCommaSeparated(params.labels), + duedate: params.duedate || undefined, + reporter: params.reporter || undefined, + environment: params.environment || undefined, + customFieldId: params.customFieldId || undefined, + customFieldValue: params.customFieldValue || undefined, } return { ...baseParams, @@ -704,6 +812,16 @@ export const JiraBlock: BlockConfig = { accountId: params.accountId, } } + case 'get_users': { + return { + ...baseParams, + accountId: params.userAccountId || undefined, + startAt: params.usersStartAt ? Number.parseInt(params.usersStartAt) : undefined, + maxResults: params.usersMaxResults + ? Number.parseInt(params.usersMaxResults) + : undefined, + } + } default: return baseParams } @@ -722,6 +840,15 @@ export const JiraBlock: BlockConfig = { summary: { type: 'string', description: 'Issue summary' }, description: { type: 'string', description: 'Issue description' }, issueType: { type: 'string', description: 'Issue type' }, + // Write operation additional inputs + assignee: { type: 'string', description: 'Assignee account ID' }, + priority: { type: 'string', description: 'Priority ID or name' }, + labels: { type: 'string', description: 'Comma-separated labels for the issue' }, + duedate: { type: 'string', description: 'Due date in YYYY-MM-DD format' }, + reporter: { type: 'string', description: 'Reporter account ID' }, + environment: { type: 'string', description: 'Environment information' }, + customFieldId: { type: 'string', description: 'Custom field ID (e.g., customfield_10001)' }, + customFieldValue: { type: 'string', description: 'Value for the custom field' }, // Delete operation inputs deleteSubtasks: { type: 'string', description: 'Whether to delete subtasks (true/false)' }, // Assign/Watcher operation inputs @@ -758,6 +885,13 @@ export const JiraBlock: BlockConfig = { linkType: { type: 'string', description: 'Type of link (e.g., "Blocks", "Relates")' }, linkComment: { type: 'string', description: 'Optional comment for issue link' }, linkId: { type: 'string', description: 'Link ID for delete operation' }, + // Get Users operation inputs + userAccountId: { + type: 'string', + description: 'Account ID for specific user lookup (optional)', + }, + usersStartAt: { type: 'string', description: 'Pagination start index for users' }, + usersMaxResults: { type: 'string', description: 'Maximum users to return' }, }, outputs: { // Common outputs across all Jira operations @@ -834,6 +968,12 @@ export const JiraBlock: BlockConfig = { // jira_add_watcher, jira_remove_watcher outputs watcherAccountId: { type: 'string', description: 'Watcher account ID' }, + // jira_get_users outputs + users: { + type: 'json', + description: 'Array of users with accountId, displayName, emailAddress, active status', + }, + // jira_bulk_read outputs // Note: bulk_read returns an array in the output field, each item contains: // ts, issueKey, summary, description, status, assignee, created, updated diff --git a/apps/sim/tools/jira/get_users.ts b/apps/sim/tools/jira/get_users.ts new file mode 100644 index 000000000..246ef1693 --- /dev/null +++ b/apps/sim/tools/jira/get_users.ts @@ -0,0 +1,217 @@ +import { getJiraCloudId } from '@/tools/jira/utils' +import type { ToolConfig, ToolResponse } from '@/tools/types' + +export interface JiraGetUsersParams { + accessToken: string + domain: string + accountId?: string + startAt?: number + maxResults?: number + cloudId?: string +} + +export interface JiraUser { + accountId: string + accountType?: string + active: boolean + displayName: string + emailAddress?: string + avatarUrls?: { + '16x16'?: string + '24x24'?: string + '32x32'?: string + '48x48'?: string + } + timeZone?: string + self?: string +} + +export interface JiraGetUsersResponse extends ToolResponse { + output: { + ts: string + users: JiraUser[] + total?: number + startAt?: number + maxResults?: number + } +} + +export const jiraGetUsersTool: ToolConfig = { + id: 'jira_get_users', + name: 'Jira Get Users', + description: + 'Get Jira users. If an account ID is provided, returns a single user. Otherwise, returns a list of all users.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'jira', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token for Jira', + }, + domain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Jira domain (e.g., yourcompany.atlassian.net)', + }, + accountId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Optional account ID to get a specific user. If not provided, returns all users.', + }, + startAt: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'The index of the first user to return (for pagination, default: 0)', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of users to return (default: 50)', + }, + cloudId: { + type: 'string', + required: false, + visibility: 'hidden', + description: + 'Jira Cloud ID for the instance. If not provided, it will be fetched using the domain.', + }, + }, + + request: { + url: (params: JiraGetUsersParams) => { + if (params.cloudId) { + if (params.accountId) { + return `https://api.atlassian.com/ex/jira/${params.cloudId}/rest/api/3/user?accountId=${encodeURIComponent(params.accountId)}` + } + const queryParams = new URLSearchParams() + if (params.startAt !== undefined) queryParams.append('startAt', String(params.startAt)) + if (params.maxResults !== undefined) + queryParams.append('maxResults', String(params.maxResults)) + const queryString = queryParams.toString() + return `https://api.atlassian.com/ex/jira/${params.cloudId}/rest/api/3/users/search${queryString ? `?${queryString}` : ''}` + } + return 'https://api.atlassian.com/oauth/token/accessible-resources' + }, + method: 'GET', + headers: (params: JiraGetUsersParams) => ({ + Accept: 'application/json', + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response: Response, params?: JiraGetUsersParams) => { + if (!params?.cloudId) { + const cloudId = await getJiraCloudId(params!.domain, params!.accessToken) + + let usersUrl: string + if (params!.accountId) { + usersUrl = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/user?accountId=${encodeURIComponent(params!.accountId)}` + } else { + const queryParams = new URLSearchParams() + if (params!.startAt !== undefined) queryParams.append('startAt', String(params!.startAt)) + if (params!.maxResults !== undefined) + queryParams.append('maxResults', String(params!.maxResults)) + const queryString = queryParams.toString() + usersUrl = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/users/search${queryString ? `?${queryString}` : ''}` + } + + const usersResponse = await fetch(usersUrl, { + method: 'GET', + headers: { + Accept: 'application/json', + Authorization: `Bearer ${params!.accessToken}`, + }, + }) + + if (!usersResponse.ok) { + let message = `Failed to get Jira users (${usersResponse.status})` + try { + const err = await usersResponse.json() + message = err?.errorMessages?.join(', ') || err?.message || message + } catch (_e) {} + throw new Error(message) + } + + const data = await usersResponse.json() + + const users = params!.accountId ? [data] : data + + return { + success: true, + output: { + ts: new Date().toISOString(), + users: users.map((user: any) => ({ + accountId: user.accountId, + accountType: user.accountType, + active: user.active, + displayName: user.displayName, + emailAddress: user.emailAddress, + avatarUrls: user.avatarUrls, + timeZone: user.timeZone, + self: user.self, + })), + total: params!.accountId ? 1 : users.length, + startAt: params!.startAt || 0, + maxResults: params!.maxResults || 50, + }, + } + } + + if (!response.ok) { + let message = `Failed to get Jira users (${response.status})` + try { + const err = await response.json() + message = err?.errorMessages?.join(', ') || err?.message || message + } catch (_e) {} + throw new Error(message) + } + + const data = await response.json() + + const users = params?.accountId ? [data] : data + + return { + success: true, + output: { + ts: new Date().toISOString(), + users: users.map((user: any) => ({ + accountId: user.accountId, + accountType: user.accountType, + active: user.active, + displayName: user.displayName, + emailAddress: user.emailAddress, + avatarUrls: user.avatarUrls, + timeZone: user.timeZone, + self: user.self, + })), + total: params?.accountId ? 1 : users.length, + startAt: params?.startAt || 0, + maxResults: params?.maxResults || 50, + }, + } + }, + + outputs: { + ts: { type: 'string', description: 'Timestamp of the operation' }, + users: { + type: 'json', + description: + 'Array of users with accountId, displayName, emailAddress, active status, and avatarUrls', + }, + total: { type: 'number', description: 'Total number of users returned' }, + startAt: { type: 'number', description: 'Pagination start index' }, + maxResults: { type: 'number', description: 'Maximum results per page' }, + }, +} diff --git a/apps/sim/tools/jira/index.ts b/apps/sim/tools/jira/index.ts index 3f4f64544..a9bed6699 100644 --- a/apps/sim/tools/jira/index.ts +++ b/apps/sim/tools/jira/index.ts @@ -11,6 +11,7 @@ import { jiraDeleteIssueLinkTool } from '@/tools/jira/delete_issue_link' import { jiraDeleteWorklogTool } from '@/tools/jira/delete_worklog' import { jiraGetAttachmentsTool } from '@/tools/jira/get_attachments' import { jiraGetCommentsTool } from '@/tools/jira/get_comments' +import { jiraGetUsersTool } from '@/tools/jira/get_users' import { jiraGetWorklogsTool } from '@/tools/jira/get_worklogs' import { jiraRemoveWatcherTool } from '@/tools/jira/remove_watcher' import { jiraRetrieveTool } from '@/tools/jira/retrieve' @@ -44,4 +45,5 @@ export { jiraDeleteIssueLinkTool, jiraAddWatcherTool, jiraRemoveWatcherTool, + jiraGetUsersTool, } diff --git a/apps/sim/tools/jira/types.ts b/apps/sim/tools/jira/types.ts index f0705f21c..b7d840f95 100644 --- a/apps/sim/tools/jira/types.ts +++ b/apps/sim/tools/jira/types.ts @@ -69,6 +69,12 @@ export interface JiraWriteParams { cloudId?: string issueType: string parent?: { key: string } + labels?: string[] + duedate?: string + reporter?: string + environment?: string + customFieldId?: string + customFieldValue?: string } export interface JiraWriteResponse extends ToolResponse { diff --git a/apps/sim/tools/jira/write.ts b/apps/sim/tools/jira/write.ts index 9339923d0..a9693c2b1 100644 --- a/apps/sim/tools/jira/write.ts +++ b/apps/sim/tools/jira/write.ts @@ -46,14 +46,14 @@ export const jiraWriteTool: ToolConfig = { priority: { type: 'string', required: false, - visibility: 'hidden', - description: 'Priority for the issue', + visibility: 'user-or-llm', + description: 'Priority ID or name for the issue (e.g., "10000" or "High")', }, assignee: { type: 'string', required: false, - visibility: 'hidden', - description: 'Assignee for the issue', + visibility: 'user-or-llm', + description: 'Assignee account ID for the issue', }, cloudId: { type: 'string', @@ -68,6 +68,42 @@ export const jiraWriteTool: ToolConfig = { visibility: 'hidden', description: 'Type of issue to create (e.g., Task, Story)', }, + labels: { + type: 'array', + required: false, + visibility: 'user-or-llm', + description: 'Labels for the issue (array of label names)', + }, + duedate: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Due date for the issue (format: YYYY-MM-DD)', + }, + reporter: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Reporter account ID for the issue', + }, + environment: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Environment information for the issue', + }, + customFieldId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Custom field ID (e.g., customfield_10001)', + }, + customFieldValue: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Value for the custom field', + }, }, request: { @@ -89,6 +125,12 @@ export const jiraWriteTool: ToolConfig = { cloudId: params.cloudId, issueType: params.issueType, parent: params.parent, + labels: params.labels, + duedate: params.duedate, + reporter: params.reporter, + environment: params.environment, + customFieldId: params.customFieldId, + customFieldValue: params.customFieldValue, } }, }, @@ -134,5 +176,6 @@ export const jiraWriteTool: ToolConfig = { issueKey: { type: 'string', description: 'Created issue key (e.g., PROJ-123)' }, summary: { type: 'string', description: 'Issue summary' }, url: { type: 'string', description: 'URL to the created issue' }, + assigneeId: { type: 'string', description: 'Account ID of the assigned user (if assigned)' }, }, } diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index f6830d462..88197c915 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -463,6 +463,7 @@ import { jiraDeleteWorklogTool, jiraGetAttachmentsTool, jiraGetCommentsTool, + jiraGetUsersTool, jiraGetWorklogsTool, jiraRemoveWatcherTool, jiraRetrieveTool, @@ -1478,6 +1479,7 @@ export const tools: Record = { jira_delete_issue_link: jiraDeleteIssueLinkTool, jira_add_watcher: jiraAddWatcherTool, jira_remove_watcher: jiraRemoveWatcherTool, + jira_get_users: jiraGetUsersTool, kalshi_get_markets: kalshiGetMarketsTool, kalshi_get_market: kalshiGetMarketTool, kalshi_get_events: kalshiGetEventsTool, diff --git a/apps/sim/tools/slack/list_channels.ts b/apps/sim/tools/slack/list_channels.ts index 9bdbab8c1..32fc3cbc3 100644 --- a/apps/sim/tools/slack/list_channels.ts +++ b/apps/sim/tools/slack/list_channels.ts @@ -110,10 +110,15 @@ export const slackListChannelsTool: ToolConfig channel.id) + const names = channels.map((channel: { name: string }) => channel.name) + return { success: true, output: { channels, + ids, + names, count: channels.length, }, } @@ -142,6 +147,14 @@ export const slackListChannelsTool: ToolConfig user.id) + const names = users.map((user: { name: string }) => user.name) + return { success: true, output: { users, + ids, + names, count: users.length, }, } @@ -133,6 +138,14 @@ export const slackListUsersTool: ToolConfig