mirror of
https://github.com/simstudioai/sim.git
synced 2026-03-15 03:00:33 -04:00
Compare commits
4 Commits
v0.5.108
...
improvemen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc5df60d8f | ||
|
|
adea9db89d | ||
|
|
94abc424be | ||
|
|
c1c6ed66d1 |
@@ -1014,36 +1014,4 @@ Get Jira users. If an account ID is provided, returns a single user. Otherwise,
|
||||
| `startAt` | number | Pagination start index |
|
||||
| `maxResults` | number | Maximum results per page |
|
||||
|
||||
### `jira_search_users`
|
||||
|
||||
Search for Jira users by email address or display name. Returns matching users with their accountId, displayName, and emailAddress.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `query` | string | Yes | A query string to search for users. Can be an email address, display name, or partial match. |
|
||||
| `maxResults` | number | No | Maximum number of users to return \(default: 50, max: 1000\) |
|
||||
| `startAt` | number | No | The index of the first user to return \(for pagination, default: 0\) |
|
||||
| `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 | ISO 8601 timestamp of the operation |
|
||||
| `users` | array | Array of matching Jira users |
|
||||
| ↳ `accountId` | string | Atlassian account ID of the user |
|
||||
| ↳ `displayName` | string | Display name of the user |
|
||||
| ↳ `active` | boolean | Whether the user account is active |
|
||||
| ↳ `emailAddress` | string | Email address of the user |
|
||||
| ↳ `accountType` | string | Type of account \(e.g., atlassian, app, customer\) |
|
||||
| ↳ `avatarUrl` | string | URL to the user avatar \(48x48\) |
|
||||
| ↳ `timeZone` | string | User timezone |
|
||||
| ↳ `self` | string | REST API URL for this user |
|
||||
| `total` | number | Number of users returned in this page \(may be less than total matches\) |
|
||||
| `startAt` | number | Pagination start index |
|
||||
| `maxResults` | number | Maximum results per page |
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ export const JiraBlock: BlockConfig<JiraResponse> = {
|
||||
{ label: 'Add Watcher', id: 'add_watcher' },
|
||||
{ label: 'Remove Watcher', id: 'remove_watcher' },
|
||||
{ label: 'Get Users', id: 'get_users' },
|
||||
{ label: 'Search Users', id: 'search_users' },
|
||||
],
|
||||
value: () => 'read',
|
||||
},
|
||||
@@ -674,31 +673,6 @@ Return ONLY the comment text - no explanations.`,
|
||||
placeholder: 'Maximum users to return (default: 50)',
|
||||
condition: { field: 'operation', value: 'get_users' },
|
||||
},
|
||||
// Search Users fields
|
||||
{
|
||||
id: 'searchUsersQuery',
|
||||
title: 'Search Query',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter email address or display name to search',
|
||||
condition: { field: 'operation', value: 'search_users' },
|
||||
},
|
||||
{
|
||||
id: 'searchUsersMaxResults',
|
||||
title: 'Max Results',
|
||||
type: 'short-input',
|
||||
placeholder: 'Maximum users to return (default: 50)',
|
||||
condition: { field: 'operation', value: 'search_users' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'searchUsersStartAt',
|
||||
title: 'Start At',
|
||||
type: 'short-input',
|
||||
placeholder: 'Pagination start index (default: 0)',
|
||||
condition: { field: 'operation', value: 'search_users' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Trigger SubBlocks
|
||||
...getTrigger('jira_issue_created').subBlocks,
|
||||
...getTrigger('jira_issue_updated').subBlocks,
|
||||
@@ -733,7 +707,6 @@ Return ONLY the comment text - no explanations.`,
|
||||
'jira_add_watcher',
|
||||
'jira_remove_watcher',
|
||||
'jira_get_users',
|
||||
'jira_search_users',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
@@ -794,8 +767,6 @@ Return ONLY the comment text - no explanations.`,
|
||||
return 'jira_remove_watcher'
|
||||
case 'get_users':
|
||||
return 'jira_get_users'
|
||||
case 'search_users':
|
||||
return 'jira_search_users'
|
||||
default:
|
||||
return 'jira_retrieve'
|
||||
}
|
||||
@@ -1052,18 +1023,6 @@ Return ONLY the comment text - no explanations.`,
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
case 'search_users': {
|
||||
return {
|
||||
...baseParams,
|
||||
query: params.searchUsersQuery,
|
||||
maxResults: params.searchUsersMaxResults
|
||||
? Number.parseInt(params.searchUsersMaxResults)
|
||||
: undefined,
|
||||
startAt: params.searchUsersStartAt
|
||||
? Number.parseInt(params.searchUsersStartAt)
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
default:
|
||||
return baseParams
|
||||
}
|
||||
@@ -1143,13 +1102,6 @@ Return ONLY the comment text - no explanations.`,
|
||||
},
|
||||
usersStartAt: { type: 'string', description: 'Pagination start index for users' },
|
||||
usersMaxResults: { type: 'string', description: 'Maximum users to return' },
|
||||
// Search Users operation inputs
|
||||
searchUsersQuery: {
|
||||
type: 'string',
|
||||
description: 'Search query (email address or display name)',
|
||||
},
|
||||
searchUsersMaxResults: { type: 'string', description: 'Maximum users to return from search' },
|
||||
searchUsersStartAt: { type: 'string', description: 'Pagination start index for user search' },
|
||||
},
|
||||
outputs: {
|
||||
// Common outputs across all Jira operations
|
||||
|
||||
@@ -117,10 +117,6 @@ export async function loadDeployedWorkflowState(
|
||||
resolvedWorkspaceId = wfRow?.workspaceId ?? undefined
|
||||
}
|
||||
|
||||
if (!resolvedWorkspaceId) {
|
||||
throw new Error(`Workflow ${workflowId} has no workspace`)
|
||||
}
|
||||
|
||||
const { blocks: migratedBlocks } = await applyBlockMigrations(
|
||||
state.blocks || {},
|
||||
resolvedWorkspaceId
|
||||
@@ -143,7 +139,7 @@ export async function loadDeployedWorkflowState(
|
||||
|
||||
interface MigrationContext {
|
||||
blocks: Record<string, BlockState>
|
||||
workspaceId: string
|
||||
workspaceId?: string
|
||||
migrated: boolean
|
||||
}
|
||||
|
||||
@@ -152,7 +148,7 @@ type BlockMigration = (ctx: MigrationContext) => MigrationContext | Promise<Migr
|
||||
function createMigrationPipeline(migrations: BlockMigration[]) {
|
||||
return async (
|
||||
blocks: Record<string, BlockState>,
|
||||
workspaceId: string
|
||||
workspaceId?: string
|
||||
): Promise<{ blocks: Record<string, BlockState>; migrated: boolean }> => {
|
||||
let ctx: MigrationContext = { blocks, workspaceId, migrated: false }
|
||||
for (const migration of migrations) {
|
||||
@@ -174,6 +170,7 @@ const applyBlockMigrations = createMigrationPipeline([
|
||||
}),
|
||||
|
||||
async (ctx) => {
|
||||
if (!ctx.workspaceId) return ctx
|
||||
const { blocks, migrated } = await migrateCredentialIds(ctx.blocks, ctx.workspaceId)
|
||||
return { ...ctx, blocks, migrated: ctx.migrated || migrated }
|
||||
},
|
||||
@@ -412,13 +409,9 @@ export async function loadWorkflowFromNormalizedTables(
|
||||
blocksMap[block.id] = assembled
|
||||
})
|
||||
|
||||
if (!workflowRow?.workspaceId) {
|
||||
throw new Error(`Workflow ${workflowId} has no workspace`)
|
||||
}
|
||||
|
||||
const { blocks: finalBlocks, migrated } = await applyBlockMigrations(
|
||||
blocksMap,
|
||||
workflowRow.workspaceId
|
||||
workflowRow?.workspaceId ?? undefined
|
||||
)
|
||||
|
||||
if (migrated) {
|
||||
|
||||
@@ -17,7 +17,6 @@ import { jiraGetWorklogsTool } from '@/tools/jira/get_worklogs'
|
||||
import { jiraRemoveWatcherTool } from '@/tools/jira/remove_watcher'
|
||||
import { jiraRetrieveTool } from '@/tools/jira/retrieve'
|
||||
import { jiraSearchIssuesTool } from '@/tools/jira/search_issues'
|
||||
import { jiraSearchUsersTool } from '@/tools/jira/search_users'
|
||||
import { jiraTransitionIssueTool } from '@/tools/jira/transition_issue'
|
||||
import { jiraUpdateTool } from '@/tools/jira/update'
|
||||
import { jiraUpdateCommentTool } from '@/tools/jira/update_comment'
|
||||
@@ -49,5 +48,4 @@ export {
|
||||
jiraAddWatcherTool,
|
||||
jiraRemoveWatcherTool,
|
||||
jiraGetUsersTool,
|
||||
jiraSearchUsersTool,
|
||||
}
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
import type { JiraSearchUsersParams, JiraSearchUsersResponse } from '@/tools/jira/types'
|
||||
import { TIMESTAMP_OUTPUT, USER_OUTPUT_PROPERTIES } from '@/tools/jira/types'
|
||||
import { getJiraCloudId, transformUser } from '@/tools/jira/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jiraSearchUsersTool: ToolConfig<JiraSearchUsersParams, JiraSearchUsersResponse> = {
|
||||
id: 'jira_search_users',
|
||||
name: 'Jira Search Users',
|
||||
description:
|
||||
'Search for Jira users by email address or display name. Returns matching users with their accountId, displayName, and emailAddress.',
|
||||
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)',
|
||||
},
|
||||
query: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'A query string to search for users. Can be an email address, display name, or partial match.',
|
||||
},
|
||||
maxResults: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of users to return (default: 50, max: 1000)',
|
||||
},
|
||||
startAt: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The index of the first user to return (for pagination, default: 0)',
|
||||
},
|
||||
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: JiraSearchUsersParams) => {
|
||||
if (params.cloudId) {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('query', params.query)
|
||||
if (params.maxResults !== undefined)
|
||||
queryParams.append('maxResults', String(params.maxResults))
|
||||
if (params.startAt !== undefined) queryParams.append('startAt', String(params.startAt))
|
||||
return `https://api.atlassian.com/ex/jira/${params.cloudId}/rest/api/3/user/search?${queryParams.toString()}`
|
||||
}
|
||||
return 'https://api.atlassian.com/oauth/token/accessible-resources'
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: JiraSearchUsersParams) => ({
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response, params?: JiraSearchUsersParams) => {
|
||||
const fetchUsers = async (cloudId: string) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('query', params!.query)
|
||||
if (params!.maxResults !== undefined)
|
||||
queryParams.append('maxResults', String(params!.maxResults))
|
||||
if (params!.startAt !== undefined) queryParams.append('startAt', String(params!.startAt))
|
||||
|
||||
const usersUrl = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/user/search?${queryParams.toString()}`
|
||||
|
||||
const usersResponse = await fetch(usersUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${params!.accessToken}`,
|
||||
},
|
||||
})
|
||||
|
||||
if (!usersResponse.ok) {
|
||||
let message = `Failed to search Jira users (${usersResponse.status})`
|
||||
try {
|
||||
const err = await usersResponse.json()
|
||||
message = err?.errorMessages?.join(', ') || err?.message || message
|
||||
} catch (_e) {}
|
||||
throw new Error(message)
|
||||
}
|
||||
|
||||
return usersResponse.json()
|
||||
}
|
||||
|
||||
let data: any
|
||||
|
||||
if (!params?.cloudId) {
|
||||
const cloudId = await getJiraCloudId(params!.domain, params!.accessToken)
|
||||
data = await fetchUsers(cloudId)
|
||||
} else {
|
||||
if (!response.ok) {
|
||||
let message = `Failed to search Jira users (${response.status})`
|
||||
try {
|
||||
const err = await response.json()
|
||||
message = err?.errorMessages?.join(', ') || err?.message || message
|
||||
} catch (_e) {}
|
||||
throw new Error(message)
|
||||
}
|
||||
data = await response.json()
|
||||
}
|
||||
|
||||
const users = Array.isArray(data) ? data.filter(Boolean) : []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
users: users.map((user: any) => ({
|
||||
...(transformUser(user) ?? { accountId: '', displayName: '' }),
|
||||
self: user.self ?? null,
|
||||
})),
|
||||
total: users.length,
|
||||
startAt: params?.startAt ?? 0,
|
||||
maxResults: params?.maxResults ?? 50,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: TIMESTAMP_OUTPUT,
|
||||
users: {
|
||||
type: 'array',
|
||||
description: 'Array of matching Jira users',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...USER_OUTPUT_PROPERTIES,
|
||||
self: {
|
||||
type: 'string',
|
||||
description: 'REST API URL for this user',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
total: {
|
||||
type: 'number',
|
||||
description: 'Number of users returned in this page (may be less than total matches)',
|
||||
},
|
||||
startAt: { type: 'number', description: 'Pagination start index' },
|
||||
maxResults: { type: 'number', description: 'Maximum results per page' },
|
||||
},
|
||||
}
|
||||
@@ -1549,34 +1549,6 @@ export interface JiraGetUsersParams {
|
||||
cloudId?: string
|
||||
}
|
||||
|
||||
export interface JiraSearchUsersParams {
|
||||
accessToken: string
|
||||
domain: string
|
||||
query: string
|
||||
maxResults?: number
|
||||
startAt?: number
|
||||
cloudId?: string
|
||||
}
|
||||
|
||||
export interface JiraSearchUsersResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
users: Array<{
|
||||
accountId: string
|
||||
accountType?: string | null
|
||||
active?: boolean | null
|
||||
displayName: string
|
||||
emailAddress?: string | null
|
||||
avatarUrl?: string | null
|
||||
timeZone?: string | null
|
||||
self?: string | null
|
||||
}>
|
||||
total: number
|
||||
startAt: number
|
||||
maxResults: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface JiraGetUsersResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
@@ -1622,4 +1594,3 @@ export type JiraResponse =
|
||||
| JiraAddWatcherResponse
|
||||
| JiraRemoveWatcherResponse
|
||||
| JiraGetUsersResponse
|
||||
| JiraSearchUsersResponse
|
||||
|
||||
@@ -1085,7 +1085,6 @@ import {
|
||||
jiraRemoveWatcherTool,
|
||||
jiraRetrieveTool,
|
||||
jiraSearchIssuesTool,
|
||||
jiraSearchUsersTool,
|
||||
jiraTransitionIssueTool,
|
||||
jiraUpdateCommentTool,
|
||||
jiraUpdateTool,
|
||||
@@ -2537,7 +2536,6 @@ export const tools: Record<string, ToolConfig> = {
|
||||
jira_add_watcher: jiraAddWatcherTool,
|
||||
jira_remove_watcher: jiraRemoveWatcherTool,
|
||||
jira_get_users: jiraGetUsersTool,
|
||||
jira_search_users: jiraSearchUsersTool,
|
||||
jsm_get_service_desks: jsmGetServiceDesksTool,
|
||||
jsm_get_request_types: jsmGetRequestTypesTool,
|
||||
jsm_get_request_type_fields: jsmGetRequestTypeFieldsTool,
|
||||
|
||||
Reference in New Issue
Block a user