Skip to content

Freshservice extended implementation #17602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions components/freshdesk/actions/update-ticket/update-ticket.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "freshdesk-update-ticket",
name: "Update a Ticket",
description: "Update status, priority, subject, description, agent, group, etc. [See the documentation](https://developers.freshdesk.com/api/#update_ticket).",
version: "0.0.1",
version: "0.0.2",
type: "action",
props: {
freshdesk,
Expand Down Expand Up @@ -71,6 +71,19 @@ export default {
description: "Used when creating a contact with phone but no email.",
optional: true,
},
internalNote: {
type: "boolean",
label: "Internal note (private)",
description: "If enabled, the comment will be added as an internal note (not visible to requester).",
optional: true,
default: false,
},
noteBody: {
type: "string",
label: "Note Body",
description: "The content of the internal note to add.",
optional: true,
},
type: {
type: "string",
label: "Type",
Expand All @@ -95,28 +108,44 @@ export default {
const {
freshdesk,
ticketId,
internalNote,
noteBody,
...fields
} = this;

const data = removeNullEntries(fields);

const ticketName = await freshdesk.getTicketName(ticketId);

if (internalNote && noteBody) {
const response = await freshdesk._makeRequest({
$,
method: "POST",
url: `/tickets/${ticketId}/notes`,
data: {
body: noteBody,
private: true,
},
});

$.export("$summary", `Internal note added to ticket "${ticketName}" (ID: ${ticketId})`);
return response;
}
Comment on lines +120 to +133
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for required noteBody when internalNote is enabled

When internalNote is true but noteBody is empty or not provided, the code silently falls through to the ticket update logic. This could confuse users who expect to add a note.

Consider adding validation similar to the Freshservice implementation:

 if (internalNote && noteBody) {
+if (internalNote) {
+  if (!noteBody) {
+    throw new Error("Note Body is required when Internal Note is enabled");
+  }
   const response = await freshdesk._makeRequest({
     $,
     method: "POST",
     url: `/tickets/${ticketId}/notes`,
     data: {
       body: noteBody,
       private: true,
     },
   });

   $.export("$summary", `Internal note added to ticket "${ticketName}" (ID: ${ticketId})`);
   return response;
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In components/freshdesk/actions/update-ticket/update-ticket.mjs around lines 120
to 133, add validation to check if noteBody is provided when internalNote is
true. If noteBody is missing or empty, throw an error or return a clear message
indicating that the note body is required before proceeding. This prevents
silent failures and ensures users are informed when they attempt to add an
internal note without content.


if (!Object.keys(data).length) {
throw new Error("Please provide at least one field to update.");
}

if (data.custom_fields) freshdesk.parseIfJSONString(data.custom_fields);

const response = await freshdesk._makeRequest({
$,
method: "PUT",
url: `/tickets/${ticketId}`,
data,
});

$.export("$summary", `Ticket "${ticketName}" (ID: ${this.ticketId}) updated successfully`);
return response;
},
};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import freshservice from "../../freshservice.app.mjs";

export default {
key: "freshservice-assign-ticket-to-agent",
name: "Assign Ticket to Agent",
description: "Assign a ticket to an agent in Freshservice. [See the documentation](https://api.freshservice.com/v2/#update_ticket)",
version: "0.0.1",
type: "action",
props: {
freshservice,
ticketId: {
propDefinition: [
freshservice,
"ticketId",
],
},
responder_id: {
propDefinition: [
freshservice,
"agentId",
],
},
},
async run({ $ }) {
const response = await this.freshservice.updateTicket({
ticketId: this.ticketId,
data: {
responder_id: this.responder_id,
},
$,
});

const ticketName = await this.freshservice.getTicketName(this.ticketId);
$.export("$summary", `Successfully assigned ticket "${ticketName}" to agent`);
return response;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import freshservice from "../../freshservice.app.mjs";

export default {
key: "freshservice-assign-ticket-to-group",
name: "Assign Ticket to Group",
description: "Assign a ticket to a group in Freshservice. [See the documentation](https://api.freshservice.com/v2/#update_ticket)",
version: "0.0.1",
type: "action",
props: {
freshservice,
ticketId: {
propDefinition: [
freshservice,
"ticketId",
],
},
group_id: {
propDefinition: [
freshservice,
"groupId",
],
},
},
async run({ $ }) {
const response = await this.freshservice.updateTicket({
ticketId: this.ticketId,
data: {
group_id: this.group_id,
},
$,
});

const ticketName = await this.freshservice.getTicketName(this.ticketId);
$.export("$summary", `Successfully assigned ticket "${ticketName}" to group`);
return response;
},
};
31 changes: 31 additions & 0 deletions components/freshservice/actions/close-ticket/close-ticket.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import freshservice from "../../freshservice.app.mjs";

export default {
key: "freshservice-close-ticket",
name: "Close Ticket",
description: "Close a ticket in Freshservice. [See the documentation](https://api.freshservice.com/v2/#update_ticket)",
version: "0.0.1",
type: "action",
props: {
freshservice,
ticketId: {
propDefinition: [
freshservice,
"ticketId",
],
},
},
async run({ $ }) {
const response = await this.freshservice.updateTicket({
ticketId: this.ticketId,
data: {
status: 5, // Closed
},
$,
});

const ticketName = await this.freshservice.getTicketName(this.ticketId);
$.export("$summary", `Successfully closed ticket "${ticketName}"`);
return response;
},
};
109 changes: 109 additions & 0 deletions components/freshservice/actions/create-company/create-company.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import freshservice from "../../freshservice.app.mjs";
import { removeNullEntries } from "../../common/utils.mjs";

export default {
key: "freshservice-create-company",
name: "Create Company",
description: "Create a new company in Freshservice. [See the documentation](https://api.freshservice.com/v2/#create_company)",
version: "0.0.1",
type: "action",
props: {
freshservice,
name: {
type: "string",
label: "Name",
description: "Name of the company",
},
description: {
type: "string",
label: "Description",
description: "Description of the company",
optional: true,
},
note: {
type: "string",
label: "Note",
description: "Note about the company",
optional: true,
},
domains: {
type: "string[]",
label: "Domains",
description: "Domains associated with the company",
optional: true,
},
primary_email: {
type: "string",
label: "Primary Email",
description: "Primary email of the company",
optional: true,
},
phone: {
type: "string",
label: "Phone",
description: "Phone number of the company",
optional: true,
},
address: {
type: "string",
label: "Address",
description: "Address of the company",
optional: true,
},
city: {
type: "string",
label: "City",
description: "City of the company",
optional: true,
},
state: {
type: "string",
label: "State",
description: "State of the company",
optional: true,
},
zip_code: {
type: "string",
label: "Zip Code",
description: "Zip code of the company",
optional: true,
},
country: {
type: "string",
label: "Country",
description: "Country of the company",
optional: true,
},
custom_fields: {
type: "object",
label: "Custom Fields",
description: "Custom fields as a JSON object",
optional: true,
},
},
async run({ $ }) {
const {
custom_fields,
domains,
...otherProps
} = this;

const data = removeNullEntries(otherProps);

if (custom_fields) {
data.custom_fields = this.freshservice.parseIfJSONString(custom_fields);
}

if (domains && domains.length > 0) {
data.domains = domains;
}

const response = await this.freshservice.createCompany({
data,
$,
});

$.export("$summary", `Successfully created company: ${response.company?.name}`);
return response;
},
};
Loading