Skip to content

Zendesk ticket tags #17603

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
wants to merge 2 commits into from
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.

🛠️ Refactor suggestion

Consider supporting both internal note and ticket update in a single action call.

The current implementation creates an either/or scenario - users can either add an internal note OR update ticket fields, but not both. This limits the action's flexibility and may not align with user expectations.

Consider refactoring to support both operations:

 if (internalNote && noteBody) {
-  const response = await freshdesk._makeRequest({
+  const noteResponse = 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;
 }

Then update the summary logic to reflect both operations when performed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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;
}
if (internalNote && noteBody) {
const noteResponse = await freshdesk._makeRequest({
$,
method: "POST",
url: `/tickets/${ticketId}/notes`,
data: {
body: noteBody,
private: true,
},
});
}
🤖 Prompt for AI Agents
In components/freshdesk/actions/update-ticket/update-ticket.mjs around lines 120
to 133, the current code only supports adding an internal note or updating
ticket fields exclusively. Refactor the code to allow both adding an internal
note and updating ticket fields within the same action call by performing both
API requests if their respective data is present. Then, update the summary
export to reflect both operations when they occur together, ensuring the action
is more flexible and meets user expectations.


if (!Object.keys(data).length) {
throw new Error("Please provide at least one field to update.");
}
Comment on lines 135 to 137
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Adjust validation logic to handle internal note scenarios.

The current validation will fail if a user only provides internal note fields since they're excluded from the data object, even though the action can still perform the internal note operation.

-if (!Object.keys(data).length) {
+if (!Object.keys(data).length && !(internalNote && noteBody)) {
   throw new Error("Please provide at least one field to update.");
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!Object.keys(data).length) {
throw new Error("Please provide at least one field to update.");
}
if (!Object.keys(data).length && !(internalNote && noteBody)) {
throw new Error("Please provide at least one field to update.");
}
🤖 Prompt for AI Agents
In components/freshdesk/actions/update-ticket/update-ticket.mjs around lines 135
to 137, the validation logic incorrectly throws an error when only internal note
fields are provided because these fields are excluded from the data object.
Modify the validation to also check if internal note fields are present and
allow the operation to proceed if either data fields or internal note fields
exist, ensuring internal note updates are not blocked.


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;
},
};

}
48 changes: 48 additions & 0 deletions components/zendesk/actions/add-ticket-tags/add-ticket-tags.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import app from "../../zendesk.app.mjs";

export default {
key: "zendesk-add-ticket-tags",
name: "Add Ticket Tags",
description: "Add tags to a ticket (appends to existing tags). [See the documentation](https://developer.zendesk.com/api-reference/ticketing/ticket-management/tags/#add-tags).",
type: "action",
version: "0.0.1",
props: {
app,
ticketId: {
propDefinition: [
app,
"ticketId",
],
},
ticketTags: {
propDefinition: [
app,
"ticketTags",
],
description: "Array of tags to add to the ticket. These will be appended to any existing tags.",
},
customSubdomain: {
propDefinition: [
app,
"customSubdomain",
],
},
},
async run({ $: step }) {
const {
ticketId,
ticketTags,
customSubdomain,
} = this;

const response = await this.app.addTicketTags({
step,
ticketId,
tags: ticketTags,
customSubdomain,
});

step.export("$summary", `Successfully added ${ticketTags.length} tag(s) to ticket ${ticketId}`);
return response;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import app from "../../zendesk.app.mjs";

export default {
key: "zendesk-remove-ticket-tags",
name: "Remove Ticket Tags",
description: "Remove specific tags from a ticket. [See the documentation](https://developer.zendesk.com/api-reference/ticketing/ticket-management/tags/#remove-tags).",
type: "action",
version: "0.0.1",
props: {
app,
ticketId: {
propDefinition: [
app,
"ticketId",
],
},
ticketTags: {
propDefinition: [
app,
"ticketTags",
],
description: "Array of tags to remove from the ticket.",
},
customSubdomain: {
propDefinition: [
app,
"customSubdomain",
],
},
},
async run({ $: step }) {
const {
ticketId,
ticketTags,
customSubdomain,
} = this;

const response = await this.app.removeTicketTags({
step,
ticketId,
tags: ticketTags,
customSubdomain,
});

step.export("$summary", `Successfully removed ${ticketTags.length} tag(s) from ticket ${ticketId}`);
return response;
},
};
47 changes: 47 additions & 0 deletions components/zendesk/actions/set-ticket-tags/set-ticket-tags.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import app from "../../zendesk.app.mjs";

export default {
key: "zendesk-set-ticket-tags",
name: "Set Ticket Tags",
description: "Set tags on a ticket (replaces all existing tags). [See the documentation](https://developer.zendesk.com/api-reference/ticketing/ticket-management/tags/#set-tags).",
type: "action",
version: "0.0.1",
props: {
app,
ticketId: {
propDefinition: [
app,
"ticketId",
],
},
ticketTags: {
propDefinition: [
app,
"ticketTags",
],
},
customSubdomain: {
propDefinition: [
app,
"customSubdomain",
],
},
},
async run({ $: step }) {
const {
ticketId,
ticketTags,
customSubdomain,
} = this;

const response = await this.app.setTicketTags({
step,
ticketId,
tags: ticketTags,
customSubdomain,
});

step.export("$summary", `Successfully set ${ticketTags.length} tag(s) on ticket ${ticketId}`);
return response;
},
};
77 changes: 74 additions & 3 deletions components/zendesk/actions/update-ticket/update-ticket.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import app from "../../zendesk.app.mjs";
export default {
key: "zendesk-update-ticket",
name: "Update Ticket",
description: "Updates a ticket. [See the documentation](https://developer.zendesk.com/api-reference/ticketing/tickets/tickets/#update-ticket).",
description: "Updates a ticket and optionally manages tags. [See the documentation](https://developer.zendesk.com/api-reference/ticketing/tickets/tickets/#update-ticket).",
type: "action",
version: "0.1.3",
version: "0.1.4",
props: {
app,
ticketId: {
Expand Down Expand Up @@ -44,6 +44,33 @@ export default {
"customSubdomain",
],
},
ticketTags: {
propDefinition: [
app,
"ticketTags",
],
},
tagAction: {
type: "string",
label: "Tag Action",
description: "How to handle the tags: set (replace all existing tags), add (append to existing tags), or remove (remove specified tags)",
options: [
{
label: "Set Tags (Replace All)",
value: "set",
},
{
label: "Add Tags (Append)",
value: "add",
},
{
label: "Remove Tags",
value: "remove",
},
],
optional: true,
default: "set",
},
},
methods: {
updateTicket({
Expand All @@ -63,6 +90,8 @@ export default {
ticketSubject,
ticketStatus,
customSubdomain,
ticketTags,
tagAction,
} = this;

const response = await this.updateTicket({
Expand All @@ -81,8 +110,50 @@ export default {
},
});

step.export("$summary", `Successfully updated ticket with ID ${response.ticket.id}`);
// Handle tag operations if tags are provided
if (ticketTags && ticketTags.length > 0) {
let tagResponse;

switch (tagAction) {
case "add":
tagResponse = await this.app.addTicketTags({
step,
ticketId,
tags: ticketTags,
customSubdomain,
});
break;
case "remove":
tagResponse = await this.app.removeTicketTags({
step,
ticketId,
tags: ticketTags,
customSubdomain,
});
break;
case "set":
default:
tagResponse = await this.app.setTicketTags({
step,
ticketId,
tags: ticketTags,
customSubdomain,
});
break;
}

// Include tag information in summary
const tagSummary = `and ${tagAction === "set" ? "set" : tagAction === "add" ? "added" : "removed"} ${ticketTags.length} tag(s)`;
step.export("$summary", `Successfully updated ticket with ID ${response.ticket.id} ${tagSummary}`);

// Include tag response in the return data
return {
ticket: response,
tags: tagResponse,
};
}

step.export("$summary", `Successfully updated ticket with ID ${response.ticket.id}`);
return response;
},
};
Loading