mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-06 21:54:01 -05:00
File diff suppressed because one or more lines are too long
@@ -51,6 +51,7 @@ import {
|
||||
IntercomIcon,
|
||||
JinaAIIcon,
|
||||
JiraIcon,
|
||||
JiraServiceManagementIcon,
|
||||
KalshiIcon,
|
||||
LinearIcon,
|
||||
LinkedInIcon,
|
||||
@@ -168,6 +169,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
intercom: IntercomIcon,
|
||||
jina: JinaAIIcon,
|
||||
jira: JiraIcon,
|
||||
jira_service_management: JiraServiceManagementIcon,
|
||||
kalshi: KalshiIcon,
|
||||
knowledge: PackageSearchIcon,
|
||||
linear: LinearIcon,
|
||||
|
||||
490
apps/docs/content/docs/en/tools/jira_service_management.mdx
Normal file
490
apps/docs/content/docs/en/tools/jira_service_management.mdx
Normal file
@@ -0,0 +1,490 @@
|
||||
---
|
||||
title: Jira Service Management
|
||||
description: Interact with Jira Service Management
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="jira_service_management"
|
||||
color="#E0E0E0"
|
||||
/>
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate with Jira Service Management for IT service management. Create and manage service requests, handle customers and organizations, track SLAs, and manage queues.
|
||||
|
||||
|
||||
|
||||
## Tools
|
||||
|
||||
### `jsm_get_service_desks`
|
||||
|
||||
Get all service desks from Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `serviceDesks` | json | Array of service desks |
|
||||
| `total` | number | Total number of service desks |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_get_request_types`
|
||||
|
||||
Get request types for a service desk in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | Yes | Service Desk ID to get request types for |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `requestTypes` | json | Array of request types |
|
||||
| `total` | number | Total number of request types |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_create_request`
|
||||
|
||||
Create a new service request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | Yes | Service Desk ID to create the request in |
|
||||
| `requestTypeId` | string | Yes | Request Type ID for the new request |
|
||||
| `summary` | string | Yes | Summary/title for the service request |
|
||||
| `description` | string | No | Description for the service request |
|
||||
| `raiseOnBehalfOf` | string | No | Account ID of customer to raise request on behalf of |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueId` | string | Created request issue ID |
|
||||
| `issueKey` | string | Created request issue key \(e.g., SD-123\) |
|
||||
| `requestTypeId` | string | Request type ID |
|
||||
| `serviceDeskId` | string | Service desk ID |
|
||||
| `success` | boolean | Whether the request was created successfully |
|
||||
| `url` | string | URL to the created request |
|
||||
|
||||
### `jsm_get_request`
|
||||
|
||||
Get a single service request from Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
|
||||
### `jsm_get_requests`
|
||||
|
||||
Get multiple service requests from Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | No | Filter by service desk ID |
|
||||
| `requestOwnership` | string | No | Filter by ownership: OWNED_REQUESTS, PARTICIPATED_REQUESTS, ORGANIZATION, ALL_REQUESTS |
|
||||
| `requestStatus` | string | No | Filter by status: OPEN, CLOSED, ALL |
|
||||
| `searchTerm` | string | No | Search term to filter requests |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `requests` | json | Array of service requests |
|
||||
| `total` | number | Total number of requests |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_add_comment`
|
||||
|
||||
Add a comment (public or internal) to a service request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `body` | string | Yes | Comment body text |
|
||||
| `isPublic` | boolean | Yes | Whether the comment is public \(visible to customer\) or internal |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `commentId` | string | Created comment ID |
|
||||
| `body` | string | Comment body text |
|
||||
| `isPublic` | boolean | Whether the comment is public |
|
||||
| `success` | boolean | Whether the comment was added successfully |
|
||||
|
||||
### `jsm_get_comments`
|
||||
|
||||
Get comments for a service request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `isPublic` | boolean | No | Filter to only public comments |
|
||||
| `internal` | boolean | No | Filter to only internal comments |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `comments` | json | Array of comments |
|
||||
| `total` | number | Total number of comments |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_get_customers`
|
||||
|
||||
Get customers for a service desk in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | Yes | Service Desk ID to get customers for |
|
||||
| `query` | string | No | Search query to filter customers |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `customers` | json | Array of customers |
|
||||
| `total` | number | Total number of customers |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_add_customer`
|
||||
|
||||
Add customers to a service desk in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | Yes | Service Desk ID to add customers to |
|
||||
| `emails` | string | Yes | Comma-separated email addresses to add as customers |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `serviceDeskId` | string | Service desk ID |
|
||||
| `success` | boolean | Whether customers were added successfully |
|
||||
|
||||
### `jsm_get_organizations`
|
||||
|
||||
Get organizations for a service desk in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | Yes | Service Desk ID to get organizations for |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `organizations` | json | Array of organizations |
|
||||
| `total` | number | Total number of organizations |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_create_organization`
|
||||
|
||||
Create a new organization in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `name` | string | Yes | Name of the organization to create |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `organizationId` | string | ID of the created organization |
|
||||
| `name` | string | Name of the created organization |
|
||||
| `success` | boolean | Whether the operation succeeded |
|
||||
|
||||
### `jsm_add_organization_to_service_desk`
|
||||
|
||||
Add an organization to a service desk in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | Yes | Service Desk ID to add the organization to |
|
||||
| `organizationId` | string | Yes | Organization ID to add to the service desk |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `serviceDeskId` | string | Service Desk ID |
|
||||
| `organizationId` | string | Organization ID added |
|
||||
| `success` | boolean | Whether the operation succeeded |
|
||||
|
||||
### `jsm_get_queues`
|
||||
|
||||
Get queues for a service desk in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `serviceDeskId` | string | Yes | Service Desk ID to get queues for |
|
||||
| `includeCount` | boolean | No | Include issue count for each queue |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `queues` | json | Array of queues |
|
||||
| `total` | number | Total number of queues |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_get_sla`
|
||||
|
||||
Get SLA information for a service request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `slas` | json | Array of SLA information |
|
||||
| `total` | number | Total number of SLAs |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_get_transitions`
|
||||
|
||||
Get available transitions for a service request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `transitions` | json | Array of available transitions |
|
||||
|
||||
### `jsm_transition_request`
|
||||
|
||||
Transition a service request to a new status in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `transitionId` | string | Yes | Transition ID to apply |
|
||||
| `comment` | string | No | Optional comment to add during transition |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `transitionId` | string | Applied transition ID |
|
||||
| `success` | boolean | Whether the transition was successful |
|
||||
|
||||
### `jsm_get_participants`
|
||||
|
||||
Get participants for a request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `participants` | json | Array of participants |
|
||||
| `total` | number | Total number of participants |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_add_participants`
|
||||
|
||||
Add participants to a request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `accountIds` | string | Yes | Comma-separated account IDs to add as participants |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `participants` | json | Array of added participants |
|
||||
| `success` | boolean | Whether the operation succeeded |
|
||||
|
||||
### `jsm_get_approvals`
|
||||
|
||||
Get approvals for a request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `start` | number | No | Start index for pagination \(default: 0\) |
|
||||
| `limit` | number | No | Maximum results to return \(default: 50\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `approvals` | json | Array of approvals |
|
||||
| `total` | number | Total number of approvals |
|
||||
| `isLastPage` | boolean | Whether this is the last page |
|
||||
|
||||
### `jsm_answer_approval`
|
||||
|
||||
Approve or decline an approval request in Jira Service Management
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `domain` | string | Yes | Your Jira domain \(e.g., yourcompany.atlassian.net\) |
|
||||
| `cloudId` | string | No | Jira Cloud ID for the instance |
|
||||
| `issueIdOrKey` | string | Yes | Issue ID or key \(e.g., SD-123\) |
|
||||
| `approvalId` | string | Yes | Approval ID to answer |
|
||||
| `decision` | string | Yes | Decision: "approve" or "decline" |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `ts` | string | Timestamp of the operation |
|
||||
| `issueIdOrKey` | string | Issue ID or key |
|
||||
| `approvalId` | string | Approval ID |
|
||||
| `decision` | string | Decision made \(approve/decline\) |
|
||||
| `success` | boolean | Whether the operation succeeded |
|
||||
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
- Category: `tools`
|
||||
- Type: `jira_service_management`
|
||||
@@ -46,6 +46,7 @@
|
||||
"intercom",
|
||||
"jina",
|
||||
"jira",
|
||||
"jira_service_management",
|
||||
"kalshi",
|
||||
"knowledge",
|
||||
"linear",
|
||||
|
||||
156
apps/sim/app/api/tools/jsm/approvals/route.ts
Normal file
156
apps/sim/app/api/tools/jsm/approvals/route.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmApprovalsAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
action,
|
||||
issueIdOrKey,
|
||||
approvalId,
|
||||
decision,
|
||||
start,
|
||||
limit,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!action) {
|
||||
logger.error('Missing action in request')
|
||||
return NextResponse.json({ error: 'Action is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
if (action === 'get') {
|
||||
const params = new URLSearchParams()
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/approval${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching approvals from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
approvals: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
}
|
||||
if (action === 'answer') {
|
||||
if (!approvalId) {
|
||||
logger.error('Missing approvalId in request')
|
||||
return NextResponse.json({ error: 'Approval ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!decision || !['approve', 'decline'].includes(decision)) {
|
||||
logger.error('Invalid or missing decision in request')
|
||||
return NextResponse.json(
|
||||
{ error: 'Decision is required and must be "approve" or "decline"' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/approval/${approvalId}`
|
||||
|
||||
logger.info('Answering approval:', { issueIdOrKey, approvalId, decision })
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify({ decision }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
approvalId,
|
||||
decision,
|
||||
success: true,
|
||||
approval: data,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
|
||||
} catch (error) {
|
||||
logger.error('Error in approvals operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
97
apps/sim/app/api/tools/jsm/comment/route.ts
Normal file
97
apps/sim/app/api/tools/jsm/comment/route.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmCommentAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: providedCloudId,
|
||||
issueIdOrKey,
|
||||
body: commentBody,
|
||||
isPublic,
|
||||
} = await request.json()
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!commentBody) {
|
||||
logger.error('Missing comment body in request')
|
||||
return NextResponse.json({ error: 'Comment body is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = providedCloudId || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/comment`
|
||||
|
||||
logger.info('Adding comment to:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify({
|
||||
body: commentBody,
|
||||
public: isPublic ?? true,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
commentId: data.id,
|
||||
body: data.body,
|
||||
isPublic: data.public,
|
||||
success: true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error adding comment:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
96
apps/sim/app/api/tools/jsm/comments/route.ts
Normal file
96
apps/sim/app/api/tools/jsm/comments/route.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmCommentsAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
issueIdOrKey,
|
||||
isPublic,
|
||||
internal,
|
||||
start,
|
||||
limit,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (isPublic) params.append('public', isPublic)
|
||||
if (internal) params.append('internal', internal)
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/comment${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching comments from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
comments: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching comments:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
143
apps/sim/app/api/tools/jsm/customers/route.ts
Normal file
143
apps/sim/app/api/tools/jsm/customers/route.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmCustomersAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
serviceDeskId,
|
||||
query,
|
||||
start,
|
||||
limit,
|
||||
emails,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!serviceDeskId) {
|
||||
logger.error('Missing serviceDeskId in request')
|
||||
return NextResponse.json({ error: 'Service Desk ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const parsedEmails = emails
|
||||
? typeof emails === 'string'
|
||||
? emails
|
||||
.split(',')
|
||||
.map((email: string) => email.trim())
|
||||
.filter((email: string) => email)
|
||||
: emails
|
||||
: []
|
||||
|
||||
const isAddOperation = parsedEmails.length > 0
|
||||
|
||||
if (isAddOperation) {
|
||||
const url = `${baseUrl}/servicedesk/${serviceDeskId}/customer`
|
||||
|
||||
logger.info('Adding customers to:', url, { emails: parsedEmails })
|
||||
|
||||
const requestBody: Record<string, unknown> = {
|
||||
usernames: parsedEmails,
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify(requestBody),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId,
|
||||
success: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
const params = new URLSearchParams()
|
||||
if (query) params.append('query', query)
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/servicedesk/${serviceDeskId}/customer${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching customers from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
customers: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error with customers operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
143
apps/sim/app/api/tools/jsm/organization/route.ts
Normal file
143
apps/sim/app/api/tools/jsm/organization/route.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmOrganizationAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
action,
|
||||
name,
|
||||
serviceDeskId,
|
||||
organizationId,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!action) {
|
||||
logger.error('Missing action in request')
|
||||
return NextResponse.json({ error: 'Action is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
if (action === 'create') {
|
||||
if (!name) {
|
||||
logger.error('Missing organization name in request')
|
||||
return NextResponse.json({ error: 'Organization name is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const url = `${baseUrl}/organization`
|
||||
|
||||
logger.info('Creating organization:', { name })
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify({ name }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
organizationId: data.id,
|
||||
name: data.name,
|
||||
success: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
if (action === 'add_to_service_desk') {
|
||||
if (!serviceDeskId) {
|
||||
logger.error('Missing serviceDeskId in request')
|
||||
return NextResponse.json({ error: 'Service Desk ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!organizationId) {
|
||||
logger.error('Missing organizationId in request')
|
||||
return NextResponse.json({ error: 'Organization ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const url = `${baseUrl}/servicedesk/${serviceDeskId}/organization`
|
||||
|
||||
logger.info('Adding organization to service desk:', { serviceDeskId, organizationId })
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify({ organizationId: Number.parseInt(organizationId, 10) }),
|
||||
})
|
||||
|
||||
if (response.status === 204 || response.ok) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId,
|
||||
organizationId,
|
||||
success: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
|
||||
} catch (error) {
|
||||
logger.error('Error in organization operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
84
apps/sim/app/api/tools/jsm/organizations/route.ts
Normal file
84
apps/sim/app/api/tools/jsm/organizations/route.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmOrganizationsAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { domain, accessToken, cloudId: cloudIdParam, serviceDeskId, start, limit } = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!serviceDeskId) {
|
||||
logger.error('Missing serviceDeskId in request')
|
||||
return NextResponse.json({ error: 'Service Desk ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/servicedesk/${serviceDeskId}/organization${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching organizations from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
organizations: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching organizations:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
153
apps/sim/app/api/tools/jsm/participants/route.ts
Normal file
153
apps/sim/app/api/tools/jsm/participants/route.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmParticipantsAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
action,
|
||||
issueIdOrKey,
|
||||
accountIds,
|
||||
start,
|
||||
limit,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!action) {
|
||||
logger.error('Missing action in request')
|
||||
return NextResponse.json({ error: 'Action is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
if (action === 'get') {
|
||||
const params = new URLSearchParams()
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/participant${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching participants from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
participants: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
}
|
||||
if (action === 'add') {
|
||||
if (!accountIds) {
|
||||
logger.error('Missing accountIds in request')
|
||||
return NextResponse.json({ error: 'Account IDs are required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const parsedAccountIds =
|
||||
typeof accountIds === 'string'
|
||||
? accountIds
|
||||
.split(',')
|
||||
.map((id: string) => id.trim())
|
||||
.filter((id: string) => id)
|
||||
: accountIds
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/participant`
|
||||
|
||||
logger.info('Adding participants to:', url, { accountIds: parsedAccountIds })
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify({ accountIds: parsedAccountIds }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
participants: data.values || [],
|
||||
success: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
|
||||
} catch (error) {
|
||||
logger.error('Error in participants operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
93
apps/sim/app/api/tools/jsm/queues/route.ts
Normal file
93
apps/sim/app/api/tools/jsm/queues/route.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmQueuesAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
serviceDeskId,
|
||||
includeCount,
|
||||
start,
|
||||
limit,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!serviceDeskId) {
|
||||
logger.error('Missing serviceDeskId in request')
|
||||
return NextResponse.json({ error: 'Service Desk ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (includeCount) params.append('includeCount', includeCount)
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/servicedesk/${serviceDeskId}/queue${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching queues from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
queues: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching queues:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
144
apps/sim/app/api/tools/jsm/request/route.ts
Normal file
144
apps/sim/app/api/tools/jsm/request/route.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmRequestAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
issueIdOrKey,
|
||||
serviceDeskId,
|
||||
requestTypeId,
|
||||
summary,
|
||||
description,
|
||||
raiseOnBehalfOf,
|
||||
requestFieldValues,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const isCreateOperation = serviceDeskId && requestTypeId && summary
|
||||
|
||||
if (isCreateOperation) {
|
||||
const url = `${baseUrl}/request`
|
||||
|
||||
logger.info('Creating request at:', url)
|
||||
|
||||
const requestBody: Record<string, unknown> = {
|
||||
serviceDeskId,
|
||||
requestTypeId,
|
||||
requestFieldValues: requestFieldValues || {
|
||||
summary,
|
||||
...(description && { description }),
|
||||
},
|
||||
}
|
||||
|
||||
if (raiseOnBehalfOf) {
|
||||
requestBody.raiseOnBehalfOf = raiseOnBehalfOf
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify(requestBody),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueId: data.issueId,
|
||||
issueKey: data.issueKey,
|
||||
requestTypeId: data.requestTypeId,
|
||||
serviceDeskId: data.serviceDeskId,
|
||||
success: true,
|
||||
url: `https://${domain}/browse/${data.issueKey}`,
|
||||
},
|
||||
})
|
||||
}
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}`
|
||||
|
||||
logger.info('Fetching request from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
request: data,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error with request operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
97
apps/sim/app/api/tools/jsm/requests/route.ts
Normal file
97
apps/sim/app/api/tools/jsm/requests/route.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmRequestsAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: cloudIdParam,
|
||||
serviceDeskId,
|
||||
requestOwnership,
|
||||
requestStatus,
|
||||
searchTerm,
|
||||
start,
|
||||
limit,
|
||||
} = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (serviceDeskId) params.append('serviceDeskId', serviceDeskId)
|
||||
if (requestOwnership && requestOwnership !== 'ALL_REQUESTS') {
|
||||
params.append('requestOwnership', requestOwnership)
|
||||
}
|
||||
if (requestStatus && requestStatus !== 'ALL') {
|
||||
params.append('requestStatus', requestStatus)
|
||||
}
|
||||
if (searchTerm) params.append('searchTerm', searchTerm)
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/request${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching requests from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
requests: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching requests:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
84
apps/sim/app/api/tools/jsm/requesttypes/route.ts
Normal file
84
apps/sim/app/api/tools/jsm/requesttypes/route.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmRequestTypesAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { domain, accessToken, cloudId: cloudIdParam, serviceDeskId, start, limit } = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!serviceDeskId) {
|
||||
logger.error('Missing serviceDeskId in request')
|
||||
return NextResponse.json({ error: 'Service Desk ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/servicedesk/${serviceDeskId}/requesttype${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching request types from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
requestTypes: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching request types:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
79
apps/sim/app/api/tools/jsm/servicedesks/route.ts
Normal file
79
apps/sim/app/api/tools/jsm/servicedesks/route.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmServiceDesksAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { domain, accessToken, cloudId: cloudIdParam, start, limit } = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/servicedesk${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching service desks from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDesks: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching service desks:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
85
apps/sim/app/api/tools/jsm/sla/route.ts
Normal file
85
apps/sim/app/api/tools/jsm/sla/route.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmSlaAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { domain, accessToken, cloudId: cloudIdParam, issueIdOrKey, start, limit } = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (start) params.append('start', start)
|
||||
if (limit) params.append('limit', limit)
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/sla${params.toString() ? `?${params.toString()}` : ''}`
|
||||
|
||||
logger.info('Fetching SLA info from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
slas: data.values || [],
|
||||
total: data.size || 0,
|
||||
isLastPage: data.isLastPage ?? true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching SLA info:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
100
apps/sim/app/api/tools/jsm/transition/route.ts
Normal file
100
apps/sim/app/api/tools/jsm/transition/route.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmTransitionAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const {
|
||||
domain,
|
||||
accessToken,
|
||||
cloudId: providedCloudId,
|
||||
issueIdOrKey,
|
||||
transitionId,
|
||||
comment,
|
||||
} = await request.json()
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!transitionId) {
|
||||
logger.error('Missing transitionId in request')
|
||||
return NextResponse.json({ error: 'Transition ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = providedCloudId || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/transition`
|
||||
|
||||
logger.info('Transitioning request at:', url)
|
||||
|
||||
const body: Record<string, unknown> = {
|
||||
id: transitionId,
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
body.additionalComment = {
|
||||
body: comment,
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
transitionId,
|
||||
success: true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error transitioning request:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
79
apps/sim/app/api/tools/jsm/transitions/route.ts
Normal file
79
apps/sim/app/api/tools/jsm/transitions/route.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JsmTransitionsAPI')
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { domain, accessToken, cloudId: cloudIdParam, issueIdOrKey } = body
|
||||
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueIdOrKey) {
|
||||
logger.error('Missing issueIdOrKey in request')
|
||||
return NextResponse.json({ error: 'Issue ID or key is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const baseUrl = getJsmApiBaseUrl(cloudId)
|
||||
|
||||
const url = `${baseUrl}/request/${issueIdOrKey}/transition`
|
||||
|
||||
logger.info('Fetching transitions from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: getJsmHeaders(accessToken),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('JSM API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: errorText,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey,
|
||||
transitions: data.values || [],
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching transitions:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error instanceof Error ? error.message : 'Internal server error',
|
||||
success: false,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
687
apps/sim/blocks/blocks/jira_service_management.ts
Normal file
687
apps/sim/blocks/blocks/jira_service_management.ts
Normal file
@@ -0,0 +1,687 @@
|
||||
import { JiraServiceManagementIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
import type { JsmResponse } from '@/tools/jsm/types'
|
||||
|
||||
export const JiraServiceManagementBlock: BlockConfig<JsmResponse> = {
|
||||
type: 'jira_service_management',
|
||||
name: 'Jira Service Management',
|
||||
description: 'Interact with Jira Service Management',
|
||||
authMode: AuthMode.OAuth,
|
||||
longDescription:
|
||||
'Integrate with Jira Service Management for IT service management. Create and manage service requests, handle customers and organizations, track SLAs, and manage queues.',
|
||||
docsLink: 'https://docs.sim.ai/tools/jira-service-management',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: JiraServiceManagementIcon,
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Get Service Desks', id: 'get_service_desks' },
|
||||
{ label: 'Get Request Types', id: 'get_request_types' },
|
||||
{ label: 'Create Request', id: 'create_request' },
|
||||
{ label: 'Get Request', id: 'get_request' },
|
||||
{ label: 'Get Requests', id: 'get_requests' },
|
||||
{ label: 'Add Comment', id: 'add_comment' },
|
||||
{ label: 'Get Comments', id: 'get_comments' },
|
||||
{ label: 'Get Customers', id: 'get_customers' },
|
||||
{ label: 'Add Customer', id: 'add_customer' },
|
||||
{ label: 'Get Organizations', id: 'get_organizations' },
|
||||
{ label: 'Create Organization', id: 'create_organization' },
|
||||
{ label: 'Add Organization to Service Desk', id: 'add_organization_to_service_desk' },
|
||||
{ label: 'Get Queues', id: 'get_queues' },
|
||||
{ label: 'Get SLA', id: 'get_sla' },
|
||||
{ label: 'Get Transitions', id: 'get_transitions' },
|
||||
{ label: 'Transition Request', id: 'transition_request' },
|
||||
{ label: 'Get Participants', id: 'get_participants' },
|
||||
{ label: 'Add Participants', id: 'add_participants' },
|
||||
{ label: 'Get Approvals', id: 'get_approvals' },
|
||||
{ label: 'Answer Approval', id: 'answer_approval' },
|
||||
],
|
||||
value: () => 'get_service_desks',
|
||||
},
|
||||
{
|
||||
id: 'domain',
|
||||
title: 'Domain',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter Jira domain (e.g., simstudio.atlassian.net)',
|
||||
},
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Jira Service Management Account',
|
||||
type: 'oauth-input',
|
||||
required: true,
|
||||
serviceId: 'jira-service-management',
|
||||
requiredScopes: [
|
||||
'read:jira-user',
|
||||
'read:jira-work',
|
||||
'write:jira-work',
|
||||
'read:project:jira',
|
||||
'read:me',
|
||||
'offline_access',
|
||||
'read:issue:jira',
|
||||
'read:status:jira',
|
||||
'read:user:jira',
|
||||
'read:issue-details:jira',
|
||||
'write:comment:jira',
|
||||
'read:comment:jira',
|
||||
'read:servicedesk:jira-service-management',
|
||||
'read:requesttype:jira-service-management',
|
||||
'read:request:jira-service-management',
|
||||
'write:request:jira-service-management',
|
||||
'read:request.comment:jira-service-management',
|
||||
'write:request.comment:jira-service-management',
|
||||
'read:customer:jira-service-management',
|
||||
'write:customer:jira-service-management',
|
||||
'read:servicedesk.customer:jira-service-management',
|
||||
'write:servicedesk.customer:jira-service-management',
|
||||
'read:organization:jira-service-management',
|
||||
'write:organization:jira-service-management',
|
||||
'read:servicedesk.organization:jira-service-management',
|
||||
'write:servicedesk.organization:jira-service-management',
|
||||
'read:queue:jira-service-management',
|
||||
'read:request.sla:jira-service-management',
|
||||
'read:request.status:jira-service-management',
|
||||
'write:request.status:jira-service-management',
|
||||
'read:request.participant:jira-service-management',
|
||||
'write:request.participant:jira-service-management',
|
||||
'read:request.approval:jira-service-management',
|
||||
'write:request.approval:jira-service-management',
|
||||
],
|
||||
placeholder: 'Select Jira Service Management account',
|
||||
},
|
||||
{
|
||||
id: 'serviceDeskId',
|
||||
title: 'Service Desk ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter service desk ID',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'get_request_types',
|
||||
'create_request',
|
||||
'get_customers',
|
||||
'add_customer',
|
||||
'get_organizations',
|
||||
'add_organization_to_service_desk',
|
||||
'get_queues',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'requestTypeId',
|
||||
title: 'Request Type ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter request type ID',
|
||||
condition: { field: 'operation', value: 'create_request' },
|
||||
},
|
||||
{
|
||||
id: 'issueIdOrKey',
|
||||
title: 'Issue ID or Key',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter issue ID or key (e.g., SD-123)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'get_request',
|
||||
'add_comment',
|
||||
'get_comments',
|
||||
'get_sla',
|
||||
'get_transitions',
|
||||
'transition_request',
|
||||
'get_participants',
|
||||
'add_participants',
|
||||
'get_approvals',
|
||||
'answer_approval',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'summary',
|
||||
title: 'Summary',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter request summary',
|
||||
condition: { field: 'operation', value: 'create_request' },
|
||||
},
|
||||
{
|
||||
id: 'description',
|
||||
title: 'Description',
|
||||
type: 'long-input',
|
||||
placeholder: 'Enter request description',
|
||||
condition: { field: 'operation', value: 'create_request' },
|
||||
},
|
||||
{
|
||||
id: 'raiseOnBehalfOf',
|
||||
title: 'Raise on Behalf Of',
|
||||
type: 'short-input',
|
||||
placeholder: 'Account ID to raise request on behalf of',
|
||||
condition: { field: 'operation', value: 'create_request' },
|
||||
},
|
||||
{
|
||||
id: 'commentBody',
|
||||
title: 'Comment',
|
||||
type: 'long-input',
|
||||
required: true,
|
||||
placeholder: 'Enter comment text',
|
||||
condition: { field: 'operation', value: 'add_comment' },
|
||||
},
|
||||
{
|
||||
id: 'isPublic',
|
||||
title: 'Comment Visibility',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Public (visible to customer)', id: 'true' },
|
||||
{ label: 'Internal (agents only)', id: 'false' },
|
||||
],
|
||||
value: () => 'true',
|
||||
condition: { field: 'operation', value: 'add_comment' },
|
||||
},
|
||||
{
|
||||
id: 'emails',
|
||||
title: 'Email Addresses',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Comma-separated email addresses',
|
||||
condition: { field: 'operation', value: 'add_customer' },
|
||||
},
|
||||
{
|
||||
id: 'customerQuery',
|
||||
title: 'Search Query',
|
||||
type: 'short-input',
|
||||
placeholder: 'Search customers by name or email',
|
||||
condition: { field: 'operation', value: 'get_customers' },
|
||||
},
|
||||
{
|
||||
id: 'transitionId',
|
||||
title: 'Transition ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter transition ID',
|
||||
condition: { field: 'operation', value: 'transition_request' },
|
||||
},
|
||||
{
|
||||
id: 'transitionComment',
|
||||
title: 'Comment',
|
||||
type: 'long-input',
|
||||
placeholder: 'Add optional comment during transition',
|
||||
condition: { field: 'operation', value: 'transition_request' },
|
||||
},
|
||||
{
|
||||
id: 'requestOwnership',
|
||||
title: 'Request Ownership',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'All Requests', id: 'ALL_REQUESTS' },
|
||||
{ label: 'My Requests', id: 'OWNED_REQUESTS' },
|
||||
{ label: 'Participated', id: 'PARTICIPATED_REQUESTS' },
|
||||
{ label: 'Organization', id: 'ORGANIZATION' },
|
||||
],
|
||||
value: () => 'ALL_REQUESTS',
|
||||
condition: { field: 'operation', value: 'get_requests' },
|
||||
},
|
||||
{
|
||||
id: 'requestStatus',
|
||||
title: 'Request Status',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'All', id: 'ALL' },
|
||||
{ label: 'Open', id: 'OPEN' },
|
||||
{ label: 'Closed', id: 'CLOSED' },
|
||||
],
|
||||
value: () => 'ALL',
|
||||
condition: { field: 'operation', value: 'get_requests' },
|
||||
},
|
||||
{
|
||||
id: 'searchTerm',
|
||||
title: 'Search Term',
|
||||
type: 'short-input',
|
||||
placeholder: 'Search requests',
|
||||
condition: { field: 'operation', value: 'get_requests' },
|
||||
},
|
||||
{
|
||||
id: 'includeCount',
|
||||
title: 'Include Issue Count',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'No', id: 'false' },
|
||||
{ label: 'Yes', id: 'true' },
|
||||
],
|
||||
value: () => 'false',
|
||||
condition: { field: 'operation', value: 'get_queues' },
|
||||
},
|
||||
{
|
||||
id: 'organizationName',
|
||||
title: 'Organization Name',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter organization name',
|
||||
condition: { field: 'operation', value: 'create_organization' },
|
||||
},
|
||||
{
|
||||
id: 'organizationId',
|
||||
title: 'Organization ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter organization ID',
|
||||
condition: { field: 'operation', value: 'add_organization_to_service_desk' },
|
||||
},
|
||||
{
|
||||
id: 'participantAccountIds',
|
||||
title: 'Account IDs',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Comma-separated account IDs',
|
||||
condition: { field: 'operation', value: 'add_participants' },
|
||||
},
|
||||
{
|
||||
id: 'approvalId',
|
||||
title: 'Approval ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter approval ID',
|
||||
condition: { field: 'operation', value: 'answer_approval' },
|
||||
},
|
||||
{
|
||||
id: 'approvalDecision',
|
||||
title: 'Decision',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Approve', id: 'approve' },
|
||||
{ label: 'Decline', id: 'decline' },
|
||||
],
|
||||
value: () => 'approve',
|
||||
condition: { field: 'operation', value: 'answer_approval' },
|
||||
},
|
||||
{
|
||||
id: 'maxResults',
|
||||
title: 'Max Results',
|
||||
type: 'short-input',
|
||||
placeholder: 'Maximum results (default: 50)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'get_service_desks',
|
||||
'get_request_types',
|
||||
'get_requests',
|
||||
'get_comments',
|
||||
'get_customers',
|
||||
'get_organizations',
|
||||
'get_queues',
|
||||
'get_sla',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
'jsm_get_service_desks',
|
||||
'jsm_get_request_types',
|
||||
'jsm_create_request',
|
||||
'jsm_get_request',
|
||||
'jsm_get_requests',
|
||||
'jsm_add_comment',
|
||||
'jsm_get_comments',
|
||||
'jsm_get_customers',
|
||||
'jsm_add_customer',
|
||||
'jsm_get_organizations',
|
||||
'jsm_create_organization',
|
||||
'jsm_add_organization_to_service_desk',
|
||||
'jsm_get_queues',
|
||||
'jsm_get_sla',
|
||||
'jsm_get_transitions',
|
||||
'jsm_transition_request',
|
||||
'jsm_get_participants',
|
||||
'jsm_add_participants',
|
||||
'jsm_get_approvals',
|
||||
'jsm_answer_approval',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'get_service_desks':
|
||||
return 'jsm_get_service_desks'
|
||||
case 'get_request_types':
|
||||
return 'jsm_get_request_types'
|
||||
case 'create_request':
|
||||
return 'jsm_create_request'
|
||||
case 'get_request':
|
||||
return 'jsm_get_request'
|
||||
case 'get_requests':
|
||||
return 'jsm_get_requests'
|
||||
case 'add_comment':
|
||||
return 'jsm_add_comment'
|
||||
case 'get_comments':
|
||||
return 'jsm_get_comments'
|
||||
case 'get_customers':
|
||||
return 'jsm_get_customers'
|
||||
case 'add_customer':
|
||||
return 'jsm_add_customer'
|
||||
case 'get_organizations':
|
||||
return 'jsm_get_organizations'
|
||||
case 'create_organization':
|
||||
return 'jsm_create_organization'
|
||||
case 'add_organization_to_service_desk':
|
||||
return 'jsm_add_organization_to_service_desk'
|
||||
case 'get_queues':
|
||||
return 'jsm_get_queues'
|
||||
case 'get_sla':
|
||||
return 'jsm_get_sla'
|
||||
case 'get_transitions':
|
||||
return 'jsm_get_transitions'
|
||||
case 'transition_request':
|
||||
return 'jsm_transition_request'
|
||||
case 'get_participants':
|
||||
return 'jsm_get_participants'
|
||||
case 'add_participants':
|
||||
return 'jsm_add_participants'
|
||||
case 'get_approvals':
|
||||
return 'jsm_get_approvals'
|
||||
case 'answer_approval':
|
||||
return 'jsm_answer_approval'
|
||||
default:
|
||||
return 'jsm_get_service_desks'
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const baseParams = {
|
||||
credential: params.credential,
|
||||
domain: params.domain,
|
||||
}
|
||||
|
||||
switch (params.operation) {
|
||||
case 'get_service_desks':
|
||||
return {
|
||||
...baseParams,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'get_request_types':
|
||||
if (!params.serviceDeskId) {
|
||||
throw new Error('Service Desk ID is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'create_request':
|
||||
if (!params.serviceDeskId) {
|
||||
throw new Error('Service Desk ID is required')
|
||||
}
|
||||
if (!params.requestTypeId) {
|
||||
throw new Error('Request Type ID is required')
|
||||
}
|
||||
if (!params.summary) {
|
||||
throw new Error('Summary is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
requestTypeId: params.requestTypeId,
|
||||
summary: params.summary,
|
||||
description: params.description,
|
||||
raiseOnBehalfOf: params.raiseOnBehalfOf,
|
||||
}
|
||||
case 'get_request':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
}
|
||||
case 'get_requests':
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
requestOwnership: params.requestOwnership,
|
||||
requestStatus: params.requestStatus,
|
||||
searchTerm: params.searchTerm,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'add_comment':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
if (!params.commentBody) {
|
||||
throw new Error('Comment body is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
body: params.commentBody,
|
||||
isPublic: params.isPublic === 'true',
|
||||
}
|
||||
case 'get_comments':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'get_customers':
|
||||
if (!params.serviceDeskId) {
|
||||
throw new Error('Service Desk ID is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
query: params.customerQuery,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'add_customer': {
|
||||
if (!params.serviceDeskId) {
|
||||
throw new Error('Service Desk ID is required')
|
||||
}
|
||||
const accountIds = params.accountIds
|
||||
? params.accountIds
|
||||
.split(',')
|
||||
.map((id: string) => id.trim())
|
||||
.filter((id: string) => id)
|
||||
: undefined
|
||||
const emails = params.emails
|
||||
? params.emails
|
||||
.split(',')
|
||||
.map((email: string) => email.trim())
|
||||
.filter((email: string) => email)
|
||||
: undefined
|
||||
if ((!accountIds || accountIds.length === 0) && (!emails || emails.length === 0)) {
|
||||
throw new Error('At least one account ID or email is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
accountIds,
|
||||
emails,
|
||||
}
|
||||
}
|
||||
case 'get_organizations':
|
||||
if (!params.serviceDeskId) {
|
||||
throw new Error('Service Desk ID is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'get_queues':
|
||||
if (!params.serviceDeskId) {
|
||||
throw new Error('Service Desk ID is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
includeCount: params.includeCount === 'true',
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'get_sla':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'get_transitions':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
}
|
||||
case 'transition_request':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
if (!params.transitionId) {
|
||||
throw new Error('Transition ID is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
transitionId: params.transitionId,
|
||||
comment: params.transitionComment,
|
||||
}
|
||||
case 'create_organization':
|
||||
if (!params.organizationName) {
|
||||
throw new Error('Organization name is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
name: params.organizationName,
|
||||
}
|
||||
case 'add_organization_to_service_desk':
|
||||
if (!params.serviceDeskId) {
|
||||
throw new Error('Service Desk ID is required')
|
||||
}
|
||||
if (!params.organizationId) {
|
||||
throw new Error('Organization ID is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
organizationId: params.organizationId,
|
||||
}
|
||||
case 'get_participants':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'add_participants':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
if (!params.participantAccountIds) {
|
||||
throw new Error('Account IDs are required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
accountIds: params.participantAccountIds,
|
||||
}
|
||||
case 'get_approvals':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
limit: params.maxResults ? Number.parseInt(params.maxResults) : undefined,
|
||||
}
|
||||
case 'answer_approval':
|
||||
if (!params.issueIdOrKey) {
|
||||
throw new Error('Issue ID or key is required')
|
||||
}
|
||||
if (!params.approvalId) {
|
||||
throw new Error('Approval ID is required')
|
||||
}
|
||||
if (!params.approvalDecision) {
|
||||
throw new Error('Decision is required')
|
||||
}
|
||||
return {
|
||||
...baseParams,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
approvalId: params.approvalId,
|
||||
decision: params.approvalDecision,
|
||||
}
|
||||
default:
|
||||
return baseParams
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
domain: { type: 'string', description: 'Jira domain' },
|
||||
credential: { type: 'string', description: 'Jira Service Management access token' },
|
||||
serviceDeskId: { type: 'string', description: 'Service desk ID' },
|
||||
requestTypeId: { type: 'string', description: 'Request type ID' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
summary: { type: 'string', description: 'Request summary' },
|
||||
description: { type: 'string', description: 'Request description' },
|
||||
raiseOnBehalfOf: { type: 'string', description: 'Account ID to raise request on behalf of' },
|
||||
commentBody: { type: 'string', description: 'Comment text' },
|
||||
isPublic: { type: 'string', description: 'Whether comment is public or internal' },
|
||||
accountIds: { type: 'string', description: 'Comma-separated account IDs' },
|
||||
emails: { type: 'string', description: 'Comma-separated email addresses' },
|
||||
customerQuery: { type: 'string', description: 'Customer search query' },
|
||||
transitionId: { type: 'string', description: 'Transition ID' },
|
||||
transitionComment: { type: 'string', description: 'Transition comment' },
|
||||
requestOwnership: { type: 'string', description: 'Request ownership filter' },
|
||||
requestStatus: { type: 'string', description: 'Request status filter' },
|
||||
searchTerm: { type: 'string', description: 'Search term for requests' },
|
||||
includeCount: { type: 'string', description: 'Include issue count for queues' },
|
||||
maxResults: { type: 'string', description: 'Maximum results to return' },
|
||||
organizationName: { type: 'string', description: 'Organization name' },
|
||||
organizationId: { type: 'string', description: 'Organization ID' },
|
||||
participantAccountIds: {
|
||||
type: 'string',
|
||||
description: 'Comma-separated account IDs for participants',
|
||||
},
|
||||
approvalId: { type: 'string', description: 'Approval ID' },
|
||||
approvalDecision: { type: 'string', description: 'Approval decision (approve/decline)' },
|
||||
},
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
serviceDesks: { type: 'json', description: 'Array of service desks' },
|
||||
requestTypes: { type: 'json', description: 'Array of request types' },
|
||||
issueId: { type: 'string', description: 'Issue ID' },
|
||||
issueKey: { type: 'string', description: 'Issue key (e.g., SD-123)' },
|
||||
request: { type: 'json', description: 'Request object' },
|
||||
requests: { type: 'json', description: 'Array of requests' },
|
||||
url: { type: 'string', description: 'URL to the request' },
|
||||
commentId: { type: 'string', description: 'Comment ID' },
|
||||
body: { type: 'string', description: 'Comment body' },
|
||||
isPublic: { type: 'boolean', description: 'Whether comment is public' },
|
||||
comments: { type: 'json', description: 'Array of comments' },
|
||||
customers: { type: 'json', description: 'Array of customers' },
|
||||
organizations: { type: 'json', description: 'Array of organizations' },
|
||||
organizationId: { type: 'string', description: 'Created organization ID' },
|
||||
name: { type: 'string', description: 'Organization name' },
|
||||
queues: { type: 'json', description: 'Array of queues' },
|
||||
slas: { type: 'json', description: 'Array of SLA information' },
|
||||
transitions: { type: 'json', description: 'Array of available transitions' },
|
||||
transitionId: { type: 'string', description: 'Applied transition ID' },
|
||||
participants: { type: 'json', description: 'Array of participants' },
|
||||
approvals: { type: 'json', description: 'Array of approvals' },
|
||||
approvalId: { type: 'string', description: 'Approval ID' },
|
||||
decision: { type: 'string', description: 'Approval decision' },
|
||||
total: { type: 'number', description: 'Total count' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -55,6 +55,7 @@ import { InputTriggerBlock } from '@/blocks/blocks/input_trigger'
|
||||
import { IntercomBlock } from '@/blocks/blocks/intercom'
|
||||
import { JinaBlock } from '@/blocks/blocks/jina'
|
||||
import { JiraBlock } from '@/blocks/blocks/jira'
|
||||
import { JiraServiceManagementBlock } from '@/blocks/blocks/jira_service_management'
|
||||
import { KalshiBlock } from '@/blocks/blocks/kalshi'
|
||||
import { KnowledgeBlock } from '@/blocks/blocks/knowledge'
|
||||
import { LinearBlock } from '@/blocks/blocks/linear'
|
||||
@@ -200,6 +201,7 @@ export const registry: Record<string, BlockConfig> = {
|
||||
intercom: IntercomBlock,
|
||||
jina: JinaBlock,
|
||||
jira: JiraBlock,
|
||||
jira_service_management: JiraServiceManagementBlock,
|
||||
kalshi: KalshiBlock,
|
||||
knowledge: KnowledgeBlock,
|
||||
linear: LinearBlock,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1227,6 +1227,98 @@ export const auth = betterAuth({
|
||||
},
|
||||
},
|
||||
|
||||
// Jira Service Management provider
|
||||
{
|
||||
providerId: 'jira-service-management',
|
||||
clientId: env.JIRA_CLIENT_ID as string,
|
||||
clientSecret: env.JIRA_CLIENT_SECRET as string,
|
||||
authorizationUrl: 'https://auth.atlassian.com/authorize',
|
||||
tokenUrl: 'https://auth.atlassian.com/oauth/token',
|
||||
userInfoUrl: 'https://api.atlassian.com/me',
|
||||
scopes: [
|
||||
'read:jira-user',
|
||||
'read:jira-work',
|
||||
'write:jira-work',
|
||||
'read:project:jira',
|
||||
'read:me',
|
||||
'offline_access',
|
||||
'read:issue:jira',
|
||||
'read:status:jira',
|
||||
'read:user:jira',
|
||||
'read:issue-details:jira',
|
||||
'write:comment:jira',
|
||||
'read:comment:jira',
|
||||
'read:servicedesk:jira-service-management',
|
||||
'read:requesttype:jira-service-management',
|
||||
'read:request:jira-service-management',
|
||||
'write:request:jira-service-management',
|
||||
'read:request.comment:jira-service-management',
|
||||
'write:request.comment:jira-service-management',
|
||||
'read:customer:jira-service-management',
|
||||
'write:customer:jira-service-management',
|
||||
'read:servicedesk.customer:jira-service-management',
|
||||
'write:servicedesk.customer:jira-service-management',
|
||||
'read:organization:jira-service-management',
|
||||
'write:organization:jira-service-management',
|
||||
'read:servicedesk.organization:jira-service-management',
|
||||
'write:servicedesk.organization:jira-service-management',
|
||||
'read:organization.user:jira-service-management',
|
||||
'write:organization.user:jira-service-management',
|
||||
'read:organization.property:jira-service-management',
|
||||
'write:organization.property:jira-service-management',
|
||||
'read:organization.profile:jira-service-management',
|
||||
'write:organization.profile:jira-service-management',
|
||||
'read:queue:jira-service-management',
|
||||
'read:request.sla:jira-service-management',
|
||||
'read:request.status:jira-service-management',
|
||||
'write:request.status:jira-service-management',
|
||||
'read:request.participant:jira-service-management',
|
||||
'write:request.participant:jira-service-management',
|
||||
'read:request.approval:jira-service-management',
|
||||
'write:request.approval:jira-service-management',
|
||||
],
|
||||
responseType: 'code',
|
||||
pkce: true,
|
||||
accessType: 'offline',
|
||||
authentication: 'basic',
|
||||
prompt: 'consent',
|
||||
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/jira-service-management`,
|
||||
getUserInfo: async (tokens) => {
|
||||
try {
|
||||
const response = await fetch('https://api.atlassian.com/me', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${tokens.accessToken}`,
|
||||
},
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
logger.error('Error fetching Jira Service Management user info:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
})
|
||||
return null
|
||||
}
|
||||
|
||||
const profile = await response.json()
|
||||
|
||||
const now = new Date()
|
||||
|
||||
return {
|
||||
id: profile.account_id,
|
||||
name: profile.name || profile.display_name || 'JSM User',
|
||||
email: profile.email || `${profile.account_id}@atlassian.com`,
|
||||
image: profile.picture || undefined,
|
||||
emailVerified: true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error in Jira Service Management getUserInfo:', { error })
|
||||
return null
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// Airtable provider
|
||||
{
|
||||
providerId: 'airtable',
|
||||
|
||||
@@ -367,6 +367,55 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
|
||||
'read:field:jira',
|
||||
],
|
||||
},
|
||||
'jira-service-management': {
|
||||
name: 'Jira Service Management',
|
||||
description: 'Access Jira Service Management service desks, requests, and customers.',
|
||||
providerId: 'jira-service-management',
|
||||
icon: JiraIcon,
|
||||
baseProviderIcon: JiraIcon,
|
||||
scopes: [
|
||||
'read:jira-user',
|
||||
'read:jira-work',
|
||||
'write:jira-work',
|
||||
'read:project:jira',
|
||||
'read:me',
|
||||
'offline_access',
|
||||
'read:issue:jira',
|
||||
'read:status:jira',
|
||||
'read:user:jira',
|
||||
'read:issue-details:jira',
|
||||
'write:comment:jira',
|
||||
'read:comment:jira',
|
||||
'read:servicedesk:jira-service-management',
|
||||
'read:requesttype:jira-service-management',
|
||||
'read:request:jira-service-management',
|
||||
'write:request:jira-service-management',
|
||||
'read:request.comment:jira-service-management',
|
||||
'write:request.comment:jira-service-management',
|
||||
'read:customer:jira-service-management',
|
||||
'write:customer:jira-service-management',
|
||||
'read:servicedesk.customer:jira-service-management',
|
||||
'write:servicedesk.customer:jira-service-management',
|
||||
'read:organization:jira-service-management',
|
||||
'write:organization:jira-service-management',
|
||||
'read:servicedesk.organization:jira-service-management',
|
||||
'write:servicedesk.organization:jira-service-management',
|
||||
'read:organization.user:jira-service-management',
|
||||
'write:organization.user:jira-service-management',
|
||||
'read:organization.property:jira-service-management',
|
||||
'write:organization.property:jira-service-management',
|
||||
'read:organization.profile:jira-service-management',
|
||||
'write:organization.profile:jira-service-management',
|
||||
'read:queue:jira-service-management',
|
||||
'read:request.sla:jira-service-management',
|
||||
'read:request.status:jira-service-management',
|
||||
'write:request.status:jira-service-management',
|
||||
'read:request.participant:jira-service-management',
|
||||
'write:request.participant:jira-service-management',
|
||||
'read:request.approval:jira-service-management',
|
||||
'write:request.approval:jira-service-management',
|
||||
],
|
||||
},
|
||||
},
|
||||
defaultService: 'jira',
|
||||
},
|
||||
|
||||
@@ -18,6 +18,7 @@ export type OAuthProvider =
|
||||
| 'airtable'
|
||||
| 'notion'
|
||||
| 'jira'
|
||||
| 'jira-service-management'
|
||||
| 'dropbox'
|
||||
| 'microsoft'
|
||||
| 'microsoft-excel'
|
||||
@@ -59,6 +60,7 @@ export type OAuthService =
|
||||
| 'airtable'
|
||||
| 'notion'
|
||||
| 'jira'
|
||||
| 'jira-service-management'
|
||||
| 'dropbox'
|
||||
| 'microsoft-excel'
|
||||
| 'microsoft-teams'
|
||||
|
||||
116
apps/sim/tools/jsm/add_comment.ts
Normal file
116
apps/sim/tools/jsm/add_comment.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import type { JsmAddCommentParams, JsmAddCommentResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddCommentTool: ToolConfig<JsmAddCommentParams, JsmAddCommentResponse> = {
|
||||
id: 'jsm_add_comment',
|
||||
name: 'JSM Add Comment',
|
||||
description: 'Add a comment (public or internal) to a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
body: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment body text',
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Whether the comment is public (visible to customer) or internal',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/comment',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
body: params.body,
|
||||
isPublic: params.isPublic,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
commentId: '',
|
||||
body: '',
|
||||
isPublic: false,
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
commentId: '',
|
||||
body: '',
|
||||
isPublic: false,
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
commentId: { type: 'string', description: 'Created comment ID' },
|
||||
body: { type: 'string', description: 'Comment body text' },
|
||||
isPublic: { type: 'boolean', description: 'Whether the comment is public' },
|
||||
success: { type: 'boolean', description: 'Whether the comment was added successfully' },
|
||||
},
|
||||
}
|
||||
100
apps/sim/tools/jsm/add_customer.ts
Normal file
100
apps/sim/tools/jsm/add_customer.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import type { JsmAddCustomerParams, JsmAddCustomerResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddCustomerTool: ToolConfig<JsmAddCustomerParams, JsmAddCustomerResponse> = {
|
||||
id: 'jsm_add_customer',
|
||||
name: 'JSM Add Customer',
|
||||
description: 'Add customers to a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Service Desk ID to add customers to',
|
||||
},
|
||||
emails: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated email addresses to add as customers',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/customers',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
emails: params.emails,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
serviceDeskId: { type: 'string', description: 'Service desk ID' },
|
||||
success: { type: 'boolean', description: 'Whether customers were added successfully' },
|
||||
},
|
||||
}
|
||||
110
apps/sim/tools/jsm/add_organization_to_service_desk.ts
Normal file
110
apps/sim/tools/jsm/add_organization_to_service_desk.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import type {
|
||||
JsmAddOrganizationToServiceDeskParams,
|
||||
JsmAddOrganizationToServiceDeskResponse,
|
||||
} from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddOrganizationToServiceDeskTool: ToolConfig<
|
||||
JsmAddOrganizationToServiceDeskParams,
|
||||
JsmAddOrganizationToServiceDeskResponse
|
||||
> = {
|
||||
id: 'jsm_add_organization_to_service_desk',
|
||||
name: 'JSM Add Organization to Service Desk',
|
||||
description: 'Add an organization to a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Service Desk ID to add the organization to',
|
||||
},
|
||||
organizationId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Organization ID to add to the service desk',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/organization',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
organizationId: params.organizationId,
|
||||
action: 'add_to_service_desk',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
organizationId: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
organizationId: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
serviceDeskId: { type: 'string', description: 'Service Desk ID' },
|
||||
organizationId: { type: 'string', description: 'Organization ID added' },
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
107
apps/sim/tools/jsm/add_participants.ts
Normal file
107
apps/sim/tools/jsm/add_participants.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import type { JsmAddParticipantsParams, JsmAddParticipantsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddParticipantsTool: ToolConfig<
|
||||
JsmAddParticipantsParams,
|
||||
JsmAddParticipantsResponse
|
||||
> = {
|
||||
id: 'jsm_add_participants',
|
||||
name: 'JSM Add Participants',
|
||||
description: 'Add participants to a request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
accountIds: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated account IDs to add as participants',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/participants',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
accountIds: params.accountIds,
|
||||
action: 'add',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
participants: { type: 'json', description: 'Array of added participants' },
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
115
apps/sim/tools/jsm/answer_approval.ts
Normal file
115
apps/sim/tools/jsm/answer_approval.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import type { JsmAnswerApprovalParams, JsmAnswerApprovalResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAnswerApprovalTool: ToolConfig<JsmAnswerApprovalParams, JsmAnswerApprovalResponse> =
|
||||
{
|
||||
id: 'jsm_answer_approval',
|
||||
name: 'JSM Answer Approval',
|
||||
description: 'Approve or decline an approval request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
approvalId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Approval ID to answer',
|
||||
},
|
||||
decision: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Decision: "approve" or "decline"',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/approvals',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
approvalId: params.approvalId,
|
||||
decision: params.decision,
|
||||
action: 'answer',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvalId: '',
|
||||
decision: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvalId: '',
|
||||
decision: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
approvalId: { type: 'string', description: 'Approval ID' },
|
||||
decision: { type: 'string', description: 'Decision made (approve/decline)' },
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
100
apps/sim/tools/jsm/create_organization.ts
Normal file
100
apps/sim/tools/jsm/create_organization.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import type { JsmCreateOrganizationParams, JsmCreateOrganizationResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmCreateOrganizationTool: ToolConfig<
|
||||
JsmCreateOrganizationParams,
|
||||
JsmCreateOrganizationResponse
|
||||
> = {
|
||||
id: 'jsm_create_organization',
|
||||
name: 'JSM Create Organization',
|
||||
description: 'Create a new organization in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the organization to create',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/organization',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
name: params.name,
|
||||
action: 'create',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
organizationId: '',
|
||||
name: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
organizationId: '',
|
||||
name: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
organizationId: { type: 'string', description: 'ID of the created organization' },
|
||||
name: { type: 'string', description: 'Name of the created organization' },
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
134
apps/sim/tools/jsm/create_request.ts
Normal file
134
apps/sim/tools/jsm/create_request.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import type { JsmCreateRequestParams, JsmCreateRequestResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmCreateRequestTool: ToolConfig<JsmCreateRequestParams, JsmCreateRequestResponse> = {
|
||||
id: 'jsm_create_request',
|
||||
name: 'JSM Create Request',
|
||||
description: 'Create a new service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Service Desk ID to create the request in',
|
||||
},
|
||||
requestTypeId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Request Type ID for the new request',
|
||||
},
|
||||
summary: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Summary/title for the service request',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Description for the service request',
|
||||
},
|
||||
raiseOnBehalfOf: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Account ID of customer to raise request on behalf of',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/request',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
requestTypeId: params.requestTypeId,
|
||||
summary: params.summary,
|
||||
description: params.description,
|
||||
raiseOnBehalfOf: params.raiseOnBehalfOf,
|
||||
requestFieldValues: params.requestFieldValues,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueId: '',
|
||||
issueKey: '',
|
||||
requestTypeId: '',
|
||||
serviceDeskId: '',
|
||||
success: false,
|
||||
url: '',
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueId: '',
|
||||
issueKey: '',
|
||||
requestTypeId: '',
|
||||
serviceDeskId: '',
|
||||
success: false,
|
||||
url: '',
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueId: { type: 'string', description: 'Created request issue ID' },
|
||||
issueKey: { type: 'string', description: 'Created request issue key (e.g., SD-123)' },
|
||||
requestTypeId: { type: 'string', description: 'Request type ID' },
|
||||
serviceDeskId: { type: 'string', description: 'Service desk ID' },
|
||||
success: { type: 'boolean', description: 'Whether the request was created successfully' },
|
||||
url: { type: 'string', description: 'URL to the created request' },
|
||||
},
|
||||
}
|
||||
114
apps/sim/tools/jsm/get_approvals.ts
Normal file
114
apps/sim/tools/jsm/get_approvals.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import type { JsmGetApprovalsParams, JsmGetApprovalsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetApprovalsTool: ToolConfig<JsmGetApprovalsParams, JsmGetApprovalsResponse> = {
|
||||
id: 'jsm_get_approvals',
|
||||
name: 'JSM Get Approvals',
|
||||
description: 'Get approvals for a request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/approvals',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
action: 'get',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvals: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvals: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
approvals: { type: 'json', description: 'Array of approvals' },
|
||||
total: { type: 'number', description: 'Total number of approvals' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
127
apps/sim/tools/jsm/get_comments.ts
Normal file
127
apps/sim/tools/jsm/get_comments.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import type { JsmGetCommentsParams, JsmGetCommentsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetCommentsTool: ToolConfig<JsmGetCommentsParams, JsmGetCommentsResponse> = {
|
||||
id: 'jsm_get_comments',
|
||||
name: 'JSM Get Comments',
|
||||
description: 'Get comments for a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter to only public comments',
|
||||
},
|
||||
internal: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter to only internal comments',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/comments',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
isPublic: params.isPublic,
|
||||
internal: params.internal,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
comments: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
comments: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
comments: { type: 'json', description: 'Array of comments' },
|
||||
total: { type: 'number', description: 'Total number of comments' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
117
apps/sim/tools/jsm/get_customers.ts
Normal file
117
apps/sim/tools/jsm/get_customers.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { JsmGetCustomersParams, JsmGetCustomersResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetCustomersTool: ToolConfig<JsmGetCustomersParams, JsmGetCustomersResponse> = {
|
||||
id: 'jsm_get_customers',
|
||||
name: 'JSM Get Customers',
|
||||
description: 'Get customers for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Service Desk ID to get customers for',
|
||||
},
|
||||
query: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search query to filter customers',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/customers',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
query: params.query,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
customers: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
customers: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
customers: { type: 'json', description: 'Array of customers' },
|
||||
total: { type: 'number', description: 'Total number of customers' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
113
apps/sim/tools/jsm/get_organizations.ts
Normal file
113
apps/sim/tools/jsm/get_organizations.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { JsmGetOrganizationsParams, JsmGetOrganizationsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetOrganizationsTool: ToolConfig<
|
||||
JsmGetOrganizationsParams,
|
||||
JsmGetOrganizationsResponse
|
||||
> = {
|
||||
id: 'jsm_get_organizations',
|
||||
name: 'JSM Get Organizations',
|
||||
description: 'Get organizations for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Service Desk ID to get organizations for',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/organizations',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
organizations: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
organizations: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
organizations: { type: 'json', description: 'Array of organizations' },
|
||||
total: { type: 'number', description: 'Total number of organizations' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
117
apps/sim/tools/jsm/get_participants.ts
Normal file
117
apps/sim/tools/jsm/get_participants.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { JsmGetParticipantsParams, JsmGetParticipantsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetParticipantsTool: ToolConfig<
|
||||
JsmGetParticipantsParams,
|
||||
JsmGetParticipantsResponse
|
||||
> = {
|
||||
id: 'jsm_get_participants',
|
||||
name: 'JSM Get Participants',
|
||||
description: 'Get participants for a request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/participants',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
action: 'get',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
participants: { type: 'json', description: 'Array of participants' },
|
||||
total: { type: 'number', description: 'Total number of participants' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
117
apps/sim/tools/jsm/get_queues.ts
Normal file
117
apps/sim/tools/jsm/get_queues.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { JsmGetQueuesParams, JsmGetQueuesResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetQueuesTool: ToolConfig<JsmGetQueuesParams, JsmGetQueuesResponse> = {
|
||||
id: 'jsm_get_queues',
|
||||
name: 'JSM Get Queues',
|
||||
description: 'Get queues for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Service Desk ID to get queues for',
|
||||
},
|
||||
includeCount: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include issue count for each queue',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/queues',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
includeCount: params.includeCount,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
queues: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
queues: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
queues: { type: 'json', description: 'Array of queues' },
|
||||
total: { type: 'number', description: 'Total number of queues' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
90
apps/sim/tools/jsm/get_request.ts
Normal file
90
apps/sim/tools/jsm/get_request.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import type { JsmGetRequestParams, JsmGetRequestResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetRequestTool: ToolConfig<JsmGetRequestParams, JsmGetRequestResponse> = {
|
||||
id: 'jsm_get_request',
|
||||
name: 'JSM Get Request',
|
||||
description: 'Get a single service request from Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/request',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
request: null,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
request: null,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
request: { type: 'json', description: 'The service request object' },
|
||||
},
|
||||
}
|
||||
113
apps/sim/tools/jsm/get_request_types.ts
Normal file
113
apps/sim/tools/jsm/get_request_types.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { JsmGetRequestTypesParams, JsmGetRequestTypesResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetRequestTypesTool: ToolConfig<
|
||||
JsmGetRequestTypesParams,
|
||||
JsmGetRequestTypesResponse
|
||||
> = {
|
||||
id: 'jsm_get_request_types',
|
||||
name: 'JSM Get Request Types',
|
||||
description: 'Get request types for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Service Desk ID to get request types for',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/requesttypes',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
requestTypes: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
requestTypes: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
requestTypes: { type: 'json', description: 'Array of request types' },
|
||||
total: { type: 'number', description: 'Total number of request types' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
132
apps/sim/tools/jsm/get_requests.ts
Normal file
132
apps/sim/tools/jsm/get_requests.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import type { JsmGetRequestsParams, JsmGetRequestsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetRequestsTool: ToolConfig<JsmGetRequestsParams, JsmGetRequestsResponse> = {
|
||||
id: 'jsm_get_requests',
|
||||
name: 'JSM Get Requests',
|
||||
description: 'Get multiple service requests from Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter by service desk ID',
|
||||
},
|
||||
requestOwnership: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'Filter by ownership: OWNED_REQUESTS, PARTICIPATED_REQUESTS, ORGANIZATION, ALL_REQUESTS',
|
||||
},
|
||||
requestStatus: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter by status: OPEN, CLOSED, ALL',
|
||||
},
|
||||
searchTerm: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search term to filter requests',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/requests',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
requestOwnership: params.requestOwnership,
|
||||
requestStatus: params.requestStatus,
|
||||
searchTerm: params.searchTerm,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
requests: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
requests: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
requests: { type: 'json', description: 'Array of service requests' },
|
||||
total: { type: 'number', description: 'Total number of requests' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
106
apps/sim/tools/jsm/get_service_desks.ts
Normal file
106
apps/sim/tools/jsm/get_service_desks.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import type { JsmGetServiceDesksParams, JsmGetServiceDesksResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetServiceDesksTool: ToolConfig<
|
||||
JsmGetServiceDesksParams,
|
||||
JsmGetServiceDesksResponse
|
||||
> = {
|
||||
id: 'jsm_get_service_desks',
|
||||
name: 'JSM Get Service Desks',
|
||||
description: 'Get all service desks from Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/servicedesks',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDesks: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDesks: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
serviceDesks: { type: 'json', description: 'Array of service desks' },
|
||||
total: { type: 'number', description: 'Total number of service desks' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
113
apps/sim/tools/jsm/get_sla.ts
Normal file
113
apps/sim/tools/jsm/get_sla.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { JsmGetSlaParams, JsmGetSlaResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetSlaTool: ToolConfig<JsmGetSlaParams, JsmGetSlaResponse> = {
|
||||
id: 'jsm_get_sla',
|
||||
name: 'JSM Get SLA',
|
||||
description: 'Get SLA information for a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start index for pagination (default: 0)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum results to return (default: 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/sla',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
slas: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
slas: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
slas: { type: 'json', description: 'Array of SLA information' },
|
||||
total: { type: 'number', description: 'Total number of SLAs' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
94
apps/sim/tools/jsm/get_transitions.ts
Normal file
94
apps/sim/tools/jsm/get_transitions.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import type { JsmGetTransitionsParams, JsmGetTransitionsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetTransitionsTool: ToolConfig<JsmGetTransitionsParams, JsmGetTransitionsResponse> =
|
||||
{
|
||||
id: 'jsm_get_transitions',
|
||||
name: 'JSM Get Transitions',
|
||||
description: 'Get available transitions for a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/transitions',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitions: [],
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitions: [],
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
transitions: { type: 'json', description: 'Array of available transitions' },
|
||||
},
|
||||
}
|
||||
43
apps/sim/tools/jsm/index.ts
Normal file
43
apps/sim/tools/jsm/index.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { jsmAddCommentTool } from '@/tools/jsm/add_comment'
|
||||
import { jsmAddCustomerTool } from '@/tools/jsm/add_customer'
|
||||
import { jsmAddOrganizationToServiceDeskTool } from '@/tools/jsm/add_organization_to_service_desk'
|
||||
import { jsmAddParticipantsTool } from '@/tools/jsm/add_participants'
|
||||
import { jsmAnswerApprovalTool } from '@/tools/jsm/answer_approval'
|
||||
import { jsmCreateOrganizationTool } from '@/tools/jsm/create_organization'
|
||||
import { jsmCreateRequestTool } from '@/tools/jsm/create_request'
|
||||
import { jsmGetApprovalsTool } from '@/tools/jsm/get_approvals'
|
||||
import { jsmGetCommentsTool } from '@/tools/jsm/get_comments'
|
||||
import { jsmGetCustomersTool } from '@/tools/jsm/get_customers'
|
||||
import { jsmGetOrganizationsTool } from '@/tools/jsm/get_organizations'
|
||||
import { jsmGetParticipantsTool } from '@/tools/jsm/get_participants'
|
||||
import { jsmGetQueuesTool } from '@/tools/jsm/get_queues'
|
||||
import { jsmGetRequestTool } from '@/tools/jsm/get_request'
|
||||
import { jsmGetRequestTypesTool } from '@/tools/jsm/get_request_types'
|
||||
import { jsmGetRequestsTool } from '@/tools/jsm/get_requests'
|
||||
import { jsmGetServiceDesksTool } from '@/tools/jsm/get_service_desks'
|
||||
import { jsmGetSlaTool } from '@/tools/jsm/get_sla'
|
||||
import { jsmGetTransitionsTool } from '@/tools/jsm/get_transitions'
|
||||
import { jsmTransitionRequestTool } from '@/tools/jsm/transition_request'
|
||||
|
||||
export {
|
||||
jsmAddCommentTool,
|
||||
jsmAddCustomerTool,
|
||||
jsmAddOrganizationToServiceDeskTool,
|
||||
jsmAddParticipantsTool,
|
||||
jsmAnswerApprovalTool,
|
||||
jsmCreateOrganizationTool,
|
||||
jsmCreateRequestTool,
|
||||
jsmGetApprovalsTool,
|
||||
jsmGetCommentsTool,
|
||||
jsmGetCustomersTool,
|
||||
jsmGetOrganizationsTool,
|
||||
jsmGetParticipantsTool,
|
||||
jsmGetQueuesTool,
|
||||
jsmGetRequestTool,
|
||||
jsmGetRequestsTool,
|
||||
jsmGetRequestTypesTool,
|
||||
jsmGetServiceDesksTool,
|
||||
jsmGetSlaTool,
|
||||
jsmGetTransitionsTool,
|
||||
jsmTransitionRequestTool,
|
||||
}
|
||||
113
apps/sim/tools/jsm/transition_request.ts
Normal file
113
apps/sim/tools/jsm/transition_request.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { JsmTransitionRequestParams, JsmTransitionRequestResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmTransitionRequestTool: ToolConfig<
|
||||
JsmTransitionRequestParams,
|
||||
JsmTransitionRequestResponse
|
||||
> = {
|
||||
id: 'jsm_transition_request',
|
||||
name: 'JSM Transition Request',
|
||||
description: 'Transition a service request to a new status in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira-service-management',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
transitionId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Transition ID to apply',
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional comment to add during transition',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/transition',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
transitionId: params.transitionId,
|
||||
comment: params.comment,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitionId: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitionId: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
transitionId: { type: 'string', description: 'Applied transition ID' },
|
||||
success: { type: 'boolean', description: 'Whether the transition was successful' },
|
||||
},
|
||||
}
|
||||
469
apps/sim/tools/jsm/types.ts
Normal file
469
apps/sim/tools/jsm/types.ts
Normal file
@@ -0,0 +1,469 @@
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
/** Common parameters for all JSM API calls */
|
||||
export interface JsmBaseParams {
|
||||
accessToken: string
|
||||
domain: string
|
||||
cloudId?: string
|
||||
}
|
||||
|
||||
/** Service Desk representation */
|
||||
export interface JsmServiceDesk {
|
||||
id: string
|
||||
projectId: string
|
||||
projectName: string
|
||||
projectKey: string
|
||||
}
|
||||
|
||||
/** Request Type representation */
|
||||
export interface JsmRequestType {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
helpText?: string
|
||||
serviceDeskId: string
|
||||
groupIds: string[]
|
||||
icon: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
/** Customer representation */
|
||||
export interface JsmCustomer {
|
||||
accountId: string
|
||||
name: string
|
||||
key: string
|
||||
emailAddress: string
|
||||
displayName: string
|
||||
active: boolean
|
||||
timeZone: string
|
||||
}
|
||||
|
||||
/** Organization representation */
|
||||
export interface JsmOrganization {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
/** Queue representation */
|
||||
export interface JsmQueue {
|
||||
id: string
|
||||
name: string
|
||||
jql: string
|
||||
fields: string[]
|
||||
issueCount: number
|
||||
}
|
||||
|
||||
/** SLA representation */
|
||||
export interface JsmSla {
|
||||
id: string
|
||||
name: string
|
||||
completedCycles: Array<{
|
||||
startTime: { iso8601: string }
|
||||
stopTime: { iso8601: string }
|
||||
breached: boolean
|
||||
}>
|
||||
ongoingCycle?: {
|
||||
startTime: { iso8601: string }
|
||||
breachTime?: { iso8601: string }
|
||||
breached: boolean
|
||||
paused: boolean
|
||||
withinCalendarHours: boolean
|
||||
goalDuration?: { millis: number; friendly: string }
|
||||
elapsedTime?: { millis: number; friendly: string }
|
||||
remainingTime?: { millis: number; friendly: string }
|
||||
}
|
||||
}
|
||||
|
||||
/** Request (ticket) representation */
|
||||
export interface JsmRequest {
|
||||
issueId: string
|
||||
issueKey: string
|
||||
requestTypeId: string
|
||||
serviceDeskId: string
|
||||
createdDate: { iso8601: string; friendly: string }
|
||||
reporter: JsmCustomer
|
||||
requestFieldValues: Array<{
|
||||
fieldId: string
|
||||
label: string
|
||||
value: unknown
|
||||
}>
|
||||
currentStatus: {
|
||||
status: string
|
||||
statusCategory: string
|
||||
statusDate: { iso8601: string; friendly: string }
|
||||
}
|
||||
}
|
||||
|
||||
/** Comment representation */
|
||||
export interface JsmComment {
|
||||
id: string
|
||||
body: string
|
||||
public: boolean
|
||||
author: {
|
||||
accountId: string
|
||||
displayName: string
|
||||
emailAddress?: string
|
||||
}
|
||||
created: { iso8601: string; friendly: string }
|
||||
}
|
||||
|
||||
/** Transition representation */
|
||||
export interface JsmTransition {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface JsmGetServiceDesksParams extends JsmBaseParams {
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetServiceDesksResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
serviceDesks: JsmServiceDesk[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetRequestTypesParams extends JsmBaseParams {
|
||||
serviceDeskId: string
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetRequestTypesResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
requestTypes: JsmRequestType[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmCreateRequestParams extends JsmBaseParams {
|
||||
serviceDeskId: string
|
||||
requestTypeId: string
|
||||
summary: string
|
||||
description?: string
|
||||
requestFieldValues?: Record<string, unknown>
|
||||
raiseOnBehalfOf?: string
|
||||
}
|
||||
|
||||
export interface JsmCreateRequestResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueId: string
|
||||
issueKey: string
|
||||
requestTypeId: string
|
||||
serviceDeskId: string
|
||||
success: boolean
|
||||
url: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetRequestParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
}
|
||||
|
||||
export interface JsmGetRequestResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
request: JsmRequest
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetRequestsParams extends JsmBaseParams {
|
||||
serviceDeskId?: string
|
||||
requestOwnership?: 'OWNED_REQUESTS' | 'PARTICIPATED_REQUESTS' | 'ORGANIZATION' | 'ALL_REQUESTS'
|
||||
requestStatus?: 'OPEN' | 'CLOSED' | 'ALL'
|
||||
searchTerm?: string
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetRequestsResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
requests: JsmRequest[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmAddCommentParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
body: string
|
||||
isPublic: boolean
|
||||
}
|
||||
|
||||
export interface JsmAddCommentResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
commentId: string
|
||||
body: string
|
||||
isPublic: boolean
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetCommentsParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
isPublic?: boolean
|
||||
internal?: boolean
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetCommentsResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
comments: JsmComment[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetCustomersParams extends JsmBaseParams {
|
||||
serviceDeskId: string
|
||||
query?: string
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetCustomersResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
customers: JsmCustomer[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmAddCustomerParams extends JsmBaseParams {
|
||||
serviceDeskId: string
|
||||
emails: string
|
||||
}
|
||||
|
||||
export interface JsmAddCustomerResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
serviceDeskId: string
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetOrganizationsParams extends JsmBaseParams {
|
||||
serviceDeskId: string
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetOrganizationsResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
organizations: JsmOrganization[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetQueuesParams extends JsmBaseParams {
|
||||
serviceDeskId: string
|
||||
includeCount?: boolean
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetQueuesResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
queues: JsmQueue[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetSlaParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetSlaResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
slas: JsmSla[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmTransitionRequestParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
transitionId: string
|
||||
comment?: string
|
||||
}
|
||||
|
||||
export interface JsmTransitionRequestResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
transitionId: string
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmGetTransitionsParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
}
|
||||
|
||||
export interface JsmGetTransitionsResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
transitions: JsmTransition[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmCreateOrganizationParams extends JsmBaseParams {
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface JsmCreateOrganizationResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
organizationId: string
|
||||
name: string
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmAddOrganizationToServiceDeskParams extends JsmBaseParams {
|
||||
serviceDeskId: string
|
||||
organizationId: string
|
||||
}
|
||||
|
||||
export interface JsmAddOrganizationToServiceDeskResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
serviceDeskId: string
|
||||
organizationId: string
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmParticipant {
|
||||
accountId: string
|
||||
displayName: string
|
||||
emailAddress?: string
|
||||
active: boolean
|
||||
}
|
||||
|
||||
export interface JsmGetParticipantsParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetParticipantsResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
participants: JsmParticipant[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmAddParticipantsParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
accountIds: string
|
||||
}
|
||||
|
||||
export interface JsmAddParticipantsResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
participants: JsmParticipant[]
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmApprover {
|
||||
accountId: string
|
||||
displayName: string
|
||||
emailAddress?: string
|
||||
approverDecision: 'pending' | 'approved' | 'declined'
|
||||
}
|
||||
|
||||
export interface JsmApproval {
|
||||
id: string
|
||||
name: string
|
||||
finalDecision: 'pending' | 'approved' | 'declined'
|
||||
canAnswerApproval: boolean
|
||||
approvers: JsmApprover[]
|
||||
createdDate?: { iso8601: string; friendly: string }
|
||||
completedDate?: { iso8601: string; friendly: string }
|
||||
}
|
||||
|
||||
export interface JsmGetApprovalsParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
start?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface JsmGetApprovalsResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
approvals: JsmApproval[]
|
||||
total: number
|
||||
isLastPage: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsmAnswerApprovalParams extends JsmBaseParams {
|
||||
issueIdOrKey: string
|
||||
approvalId: string
|
||||
decision: 'approve' | 'decline'
|
||||
}
|
||||
|
||||
export interface JsmAnswerApprovalResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
issueIdOrKey: string
|
||||
approvalId: string
|
||||
decision: string
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
/** Union type for all JSM responses */
|
||||
export type JsmResponse =
|
||||
| JsmGetServiceDesksResponse
|
||||
| JsmGetRequestTypesResponse
|
||||
| JsmCreateRequestResponse
|
||||
| JsmGetRequestResponse
|
||||
| JsmGetRequestsResponse
|
||||
| JsmAddCommentResponse
|
||||
| JsmGetCommentsResponse
|
||||
| JsmGetCustomersResponse
|
||||
| JsmAddCustomerResponse
|
||||
| JsmGetOrganizationsResponse
|
||||
| JsmGetQueuesResponse
|
||||
| JsmGetSlaResponse
|
||||
| JsmTransitionRequestResponse
|
||||
| JsmGetTransitionsResponse
|
||||
| JsmCreateOrganizationResponse
|
||||
| JsmAddOrganizationToServiceDeskResponse
|
||||
| JsmGetParticipantsResponse
|
||||
| JsmAddParticipantsResponse
|
||||
| JsmGetApprovalsResponse
|
||||
| JsmAnswerApprovalResponse
|
||||
28
apps/sim/tools/jsm/utils.ts
Normal file
28
apps/sim/tools/jsm/utils.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Shared utilities for Jira Service Management tools
|
||||
* Reuses the getJiraCloudId from the Jira integration since JSM uses the same Atlassian Cloud ID
|
||||
*/
|
||||
export { getJiraCloudId } from '@/tools/jira/utils'
|
||||
|
||||
/**
|
||||
* Build the base URL for JSM Service Desk API
|
||||
* @param cloudId - The Jira Cloud ID
|
||||
* @returns The base URL for the Service Desk API
|
||||
*/
|
||||
export function getJsmApiBaseUrl(cloudId: string): string {
|
||||
return `https://api.atlassian.com/ex/jira/${cloudId}/rest/servicedeskapi`
|
||||
}
|
||||
|
||||
/**
|
||||
* Build common headers for JSM API requests
|
||||
* @param accessToken - The OAuth access token
|
||||
* @returns Headers object for API requests
|
||||
*/
|
||||
export function getJsmHeaders(accessToken: string): Record<string, string> {
|
||||
return {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-ExperimentalApi': 'opt-in',
|
||||
}
|
||||
}
|
||||
@@ -491,6 +491,28 @@ import {
|
||||
jiraUpdateWorklogTool,
|
||||
jiraWriteTool,
|
||||
} from '@/tools/jira'
|
||||
import {
|
||||
jsmAddCommentTool,
|
||||
jsmAddCustomerTool,
|
||||
jsmAddOrganizationToServiceDeskTool,
|
||||
jsmAddParticipantsTool,
|
||||
jsmAnswerApprovalTool,
|
||||
jsmCreateOrganizationTool,
|
||||
jsmCreateRequestTool,
|
||||
jsmGetApprovalsTool,
|
||||
jsmGetCommentsTool,
|
||||
jsmGetCustomersTool,
|
||||
jsmGetOrganizationsTool,
|
||||
jsmGetParticipantsTool,
|
||||
jsmGetQueuesTool,
|
||||
jsmGetRequestsTool,
|
||||
jsmGetRequestTool,
|
||||
jsmGetRequestTypesTool,
|
||||
jsmGetServiceDesksTool,
|
||||
jsmGetSlaTool,
|
||||
jsmGetTransitionsTool,
|
||||
jsmTransitionRequestTool,
|
||||
} from '@/tools/jsm'
|
||||
import {
|
||||
kalshiAmendOrderTool,
|
||||
kalshiCancelOrderTool,
|
||||
@@ -1498,6 +1520,26 @@ export const tools: Record<string, ToolConfig> = {
|
||||
jira_add_watcher: jiraAddWatcherTool,
|
||||
jira_remove_watcher: jiraRemoveWatcherTool,
|
||||
jira_get_users: jiraGetUsersTool,
|
||||
jsm_get_service_desks: jsmGetServiceDesksTool,
|
||||
jsm_get_request_types: jsmGetRequestTypesTool,
|
||||
jsm_create_request: jsmCreateRequestTool,
|
||||
jsm_get_request: jsmGetRequestTool,
|
||||
jsm_get_requests: jsmGetRequestsTool,
|
||||
jsm_add_comment: jsmAddCommentTool,
|
||||
jsm_get_comments: jsmGetCommentsTool,
|
||||
jsm_get_customers: jsmGetCustomersTool,
|
||||
jsm_add_customer: jsmAddCustomerTool,
|
||||
jsm_get_organizations: jsmGetOrganizationsTool,
|
||||
jsm_create_organization: jsmCreateOrganizationTool,
|
||||
jsm_add_organization_to_service_desk: jsmAddOrganizationToServiceDeskTool,
|
||||
jsm_get_queues: jsmGetQueuesTool,
|
||||
jsm_get_sla: jsmGetSlaTool,
|
||||
jsm_get_transitions: jsmGetTransitionsTool,
|
||||
jsm_transition_request: jsmTransitionRequestTool,
|
||||
jsm_get_participants: jsmGetParticipantsTool,
|
||||
jsm_add_participants: jsmAddParticipantsTool,
|
||||
jsm_get_approvals: jsmGetApprovalsTool,
|
||||
jsm_answer_approval: jsmAnswerApprovalTool,
|
||||
kalshi_get_markets: kalshiGetMarketsTool,
|
||||
kalshi_get_market: kalshiGetMarketTool,
|
||||
kalshi_get_events: kalshiGetEventsTool,
|
||||
|
||||
Reference in New Issue
Block a user