mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-07 22:24:06 -05:00
File diff suppressed because one or more lines are too long
@@ -51,6 +51,7 @@ import {
|
|||||||
IntercomIcon,
|
IntercomIcon,
|
||||||
JinaAIIcon,
|
JinaAIIcon,
|
||||||
JiraIcon,
|
JiraIcon,
|
||||||
|
JiraServiceManagementIcon,
|
||||||
KalshiIcon,
|
KalshiIcon,
|
||||||
LinearIcon,
|
LinearIcon,
|
||||||
LinkedInIcon,
|
LinkedInIcon,
|
||||||
@@ -168,6 +169,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
|||||||
intercom: IntercomIcon,
|
intercom: IntercomIcon,
|
||||||
jina: JinaAIIcon,
|
jina: JinaAIIcon,
|
||||||
jira: JiraIcon,
|
jira: JiraIcon,
|
||||||
|
jira_service_management: JiraServiceManagementIcon,
|
||||||
kalshi: KalshiIcon,
|
kalshi: KalshiIcon,
|
||||||
knowledge: PackageSearchIcon,
|
knowledge: PackageSearchIcon,
|
||||||
linear: LinearIcon,
|
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",
|
"intercom",
|
||||||
"jina",
|
"jina",
|
||||||
"jira",
|
"jira",
|
||||||
|
"jira_service_management",
|
||||||
"kalshi",
|
"kalshi",
|
||||||
"knowledge",
|
"knowledge",
|
||||||
"linear",
|
"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 { IntercomBlock } from '@/blocks/blocks/intercom'
|
||||||
import { JinaBlock } from '@/blocks/blocks/jina'
|
import { JinaBlock } from '@/blocks/blocks/jina'
|
||||||
import { JiraBlock } from '@/blocks/blocks/jira'
|
import { JiraBlock } from '@/blocks/blocks/jira'
|
||||||
|
import { JiraServiceManagementBlock } from '@/blocks/blocks/jira_service_management'
|
||||||
import { KalshiBlock } from '@/blocks/blocks/kalshi'
|
import { KalshiBlock } from '@/blocks/blocks/kalshi'
|
||||||
import { KnowledgeBlock } from '@/blocks/blocks/knowledge'
|
import { KnowledgeBlock } from '@/blocks/blocks/knowledge'
|
||||||
import { LinearBlock } from '@/blocks/blocks/linear'
|
import { LinearBlock } from '@/blocks/blocks/linear'
|
||||||
@@ -200,6 +201,7 @@ export const registry: Record<string, BlockConfig> = {
|
|||||||
intercom: IntercomBlock,
|
intercom: IntercomBlock,
|
||||||
jina: JinaBlock,
|
jina: JinaBlock,
|
||||||
jira: JiraBlock,
|
jira: JiraBlock,
|
||||||
|
jira_service_management: JiraServiceManagementBlock,
|
||||||
kalshi: KalshiBlock,
|
kalshi: KalshiBlock,
|
||||||
knowledge: KnowledgeBlock,
|
knowledge: KnowledgeBlock,
|
||||||
linear: LinearBlock,
|
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
|
// Airtable provider
|
||||||
{
|
{
|
||||||
providerId: 'airtable',
|
providerId: 'airtable',
|
||||||
|
|||||||
@@ -367,6 +367,55 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
|
|||||||
'read:field:jira',
|
'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',
|
defaultService: 'jira',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export type OAuthProvider =
|
|||||||
| 'airtable'
|
| 'airtable'
|
||||||
| 'notion'
|
| 'notion'
|
||||||
| 'jira'
|
| 'jira'
|
||||||
|
| 'jira-service-management'
|
||||||
| 'dropbox'
|
| 'dropbox'
|
||||||
| 'microsoft'
|
| 'microsoft'
|
||||||
| 'microsoft-excel'
|
| 'microsoft-excel'
|
||||||
@@ -59,6 +60,7 @@ export type OAuthService =
|
|||||||
| 'airtable'
|
| 'airtable'
|
||||||
| 'notion'
|
| 'notion'
|
||||||
| 'jira'
|
| 'jira'
|
||||||
|
| 'jira-service-management'
|
||||||
| 'dropbox'
|
| 'dropbox'
|
||||||
| 'microsoft-excel'
|
| 'microsoft-excel'
|
||||||
| 'microsoft-teams'
|
| '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,
|
jiraUpdateWorklogTool,
|
||||||
jiraWriteTool,
|
jiraWriteTool,
|
||||||
} from '@/tools/jira'
|
} 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 {
|
import {
|
||||||
kalshiAmendOrderTool,
|
kalshiAmendOrderTool,
|
||||||
kalshiCancelOrderTool,
|
kalshiCancelOrderTool,
|
||||||
@@ -1498,6 +1520,26 @@ export const tools: Record<string, ToolConfig> = {
|
|||||||
jira_add_watcher: jiraAddWatcherTool,
|
jira_add_watcher: jiraAddWatcherTool,
|
||||||
jira_remove_watcher: jiraRemoveWatcherTool,
|
jira_remove_watcher: jiraRemoveWatcherTool,
|
||||||
jira_get_users: jiraGetUsersTool,
|
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_markets: kalshiGetMarketsTool,
|
||||||
kalshi_get_market: kalshiGetMarketTool,
|
kalshi_get_market: kalshiGetMarketTool,
|
||||||
kalshi_get_events: kalshiGetEventsTool,
|
kalshi_get_events: kalshiGetEventsTool,
|
||||||
|
|||||||
Reference in New Issue
Block a user