Skip to main content


 This is an application that can link tickets creating parent-child relationships.

This application is compatible with the Parent-Child FreshPlug created by Freshdesk ( the one I am aware of, anyway - see https://support.freshdesk.com/support/discussions/topics/16385/page/2 ). It can replace it. You can also switch back from this application to the Freshdesk Parent-Child application if you wish. However, you can't use both at the same time.

Main features include:





  • In a group of linked tickets, one ticket acts as a parent and the others as its children.


  • A parent cannot have another parent and a child cannot have children.


  • You can see all children when viewing a parent. You can see the parent plus all siblings when viewing a child.


  • Each linked ticket is listed with detailed information ( subject, ID, status, requester, creation/modification date, group, agent )


  • If a ticket is unlinked you can set any other ticket to be its parent ( by entering the parent id in the Ticket Properties field Parent ticket ID ). If the parent actually is a child, the parent of the current ticket will be set to the parent of the "parent". if the parent does not exist, no linking will happen.


  • If a ticket is a child it can be unlinked by deleting the Ticket Properties field Parent ticket ID.


  • The toolbar of parent tickets has a light background ( gray if no child is unresolved or reddish otherwise, as an indicator of loose-ends ). Note that nothing stops an agent from resolving/closing a parent ticket even if not all children are resolved/closed.




  • New linked tickets, can easily be created, from within the ticket view page of either the parent ticket or any of the children tickets. In any case, all new child tickets will have the same parent.


  • New linked tickets can be created, in new tabs, as New Tickets or New Emails, using the standard Freshdesk forms for that purpose ( but slightly rearranged for better usability ). The New Ticket / New Email form fields are copied from the parent ticket. Custom ticket fields are hidden. Type and Tag fields are copied. Nested Type fields are properly displayed and can be modified consistently.


  • New linked tickets can be created with the requester set to the same agent or requester as the originating ticket, to the current agent or not set ( but left to be specified when filling the form )






Instructions:

IMPORTANT: If you have installed the Parent-Child FreshPlug created by Freshdesk, disable it ( don't delete or overwrite it ) and make sure that the custom ticket fields are named as follows.

___________________
A) Navigate to Admin > Ticket Fields and create these 3 custom ticket fields ( if they don't exist already ):

A.1) Parent or Child ticket
A.2) Parent ticket ID
A.3) Child Ticket ID



  • It is suggested that Parent ticket ID is of type Number but it can also be of type Single Line Text.
    Number is preferred for taking advantage of the built-in numeric input validation of Freshdesk.




  • Parent or Child ticket and Child Ticket ID must be of type Single Line Text.





Note: Parent or Child ticket serves no purpose but exists to ensure compatibility with the Freshdesk Parent-Child application ( in case one switches back to it ). However, it is necessary for the application to work. If, in the future, you decide you want to get rid of it, all you have to do is remove a few lines from the first app.

___________________
B) Navigate to Admin > Apps > Custom Apps and create the following 2 apps:

B.1) Linked tickets
B.2) New ticket has parent



  • For the Linked tickets app select the Custom app displayed on option Ticket detail page.


  • For the New ticket has parent app select the Custom app displayed on options New Ticket Page and Outbound Email Page.





The source for each app will be posted on separate posts.

 






Linked tickets



<style type="text/css">

#linked_tickets_widget {

display: none;

}



#linked_tickets_widget .hidden {

display: none;

}



.linked_ticket {

border-top: 1px solid #ddd;

clear: both;

display: block;

font-size: 13px;

margin: 0;

padding: 4px 8px;

}



.linked_ticket.parent {

border-left: 2px dotted #ddd;

border-right: 2px dotted #ddd;

padding: 4px 6px;

}



.linked_ticket div {

margin-bottom: 4px;

}



.linked_ticket .field_description {

color: #ddd;

cursor: help;

}



.linked_ticket_subject {}



.linked_ticket_status_and_id {

float: left;

width: 75px;

}



.linked_ticket_parent {

color: #ddd;

font-size: larger;

font-weight: bold;

text-align: right;

}



.linked_ticket_child {

color: #eee;

font-size: larger;

font-weight: bold;

text-align: right;

}



.linked_ticket_status {

padding: 2px 0;

text-align: right;

}



.linked_ticket_status.id1 {

color: #999;

}



.linked_ticket_status.id2 {

color: #f50;

}



.linked_ticket_status.id3 {

color: #90a;

}



.linked_ticket_status.id4 {

color: #ddd;

}



.linked_ticket_status.id5 {

color: #ddd;

}



.linked_ticket_status.id8 {

color: #90a;

}



.linked_ticket_id,

.linked_ticket_id>a {

color: #999;

font-family: monospace;

font-size: large;

font-weight: bold;

text-align: right;

}



.linked_ticket_time_and_agent {

border-left: 1px solid #eee;

color: #999;

font-size: 90%;

margin: 0 0 0 85px;

padding: 0 0 0 10px;

}



.linked_ticket_time_and_agent>a {

color: #999;

}



.linked_ticket_time_and_agent>a:hover,

.linked_ticket_id>a:hover {

color: #004080;

}



.linked_ticket .format_date {

font-family: monospace;

font-size: 110%;

}



.linked_tickets_new {

border: 1px solid #ddd;

border-radius: 0 0 8px 8px;

color: #333;

font-size: 90%;

padding: 8px;

}



.linked_tickets_new>table {

width: 100%;

}



.linked_tickets_new caption {

padding: 0 4px 4px;

text-align: left;

}



.linked_tickets_new td {

padding: 0 4px;

}



.linked_tickets_new_agents>select {

margin: 5px 5px 0;

width: 100%;

}



#linked_tickets_widget>h3 {

display: block;

width: 270px;

padding-bottom: 8px;

}



#reload_parent-children {

display: block;

float: right;

padding: 7px;

}

</style>

<div id="linked_tickets_widget" class="widget">

<a href="javascript: void(0)" id="reload_parent-children" title=" Reload App ">&#8635;</a>

<h3 class="heading">Linked Tickets</h3>

<div class="hidden">

<input type="text" value="" name="store_name_parent" id="store_id_parent" class="store_class_parent">

<input type="text" value="" name="store_name_responder_id" id="store_id_responder_id" class="store_class_responder_id">

</div>

<div class="linked_tickets_list"></div>

<div class="linked_tickets_new"></div>

<div class="linked_tickets_new_agents"></div>

</div>

<script type="text/javascript">

// Freshdesk Instance ID: 359268

(function($) {

var LinkedTickets = Class.create();

LinkedTickets.prototype = {



initialize: function() {

jQuery('#linked_tickets_widget').insertAfter('#requester_info');

},



onSidebarLoaded: function() {

jQuery(element_custom_field_parent_or_child_ticket).closest('.field').hide(); // Compatibility

jQuery(element_custom_field_parent).closest('.field').hide();

jQuery(element_custom_field_children).closest('.field').hide();

jQuery('#linked_tickets_widget').show();

jQuery('.linked_tickets_list').html('');

jQuery('.linked_tickets_new').html('');

jQuery('.linked_tickets_new').hide();

jQuery('.linked_tickets_new_agents').html('');

jQuery('.linked_tickets_new_agents').hide();

var this_object = this;

var children_arr = [];

var value_custom_field_children = jQuery(element_custom_field_children).val();

var value_custom_field_parent = jQuery(element_custom_field_parent).val();

var value_responder_id = jQuery(element_responder_id).val();

var value_custom_field_parent_or_child_ticket = jQuery(element_custom_field_parent_or_child_ticket).val(); // Compatibility

if (value_custom_field_parent_or_child_ticket == 'Parent') {

value_custom_field_parent = '{{ticket.id}}';

jQuery(element_custom_field_parent).val(value_custom_field_parent);

}

// Store parent ID & current agent ID

jQuery(store_element_custom_field_parent).val(value_custom_field_parent);

jQuery(store_element_responder_id).val(value_responder_id);



if (value_custom_field_parent) {

if (value_custom_field_parent == '{{ticket.id}}') {

if (value_custom_field_children) {

// Current ticket is a Parent with children

jQuery('.tkt-details-sticky').css("background", "#ffffff linear-gradient(#ffffff, #ffffff, #eeeeff) repeat scroll 0 0");

h3_open = 'Children:';

h3_closed = 'This is a Parent ticket';

jQuery('#linked_tickets_widget .heading').text(h3_open);

jQuery('#linked_tickets_widget').removeClass('inactive');

jQuery(element_custom_field_parent).closest('.field').hide();

jQuery('.linked_tickets_new').show().html(this_object.ticketCreateNew(value_custom_field_parent, "Create new child ticket with the following requester:"));

children_arr = value_custom_field_children.split(',');

jQuery.each(children_arr, function(index, item) {

// Get all children

if (item != '{{ticket.id}}') {

this_object.ticketAjaxCallGetChild(item, value_custom_field_parent);

}

});

} else {

// Error: Current ticket is a parent without children => Not a parent

h3_open = 'No linked tickets';

h3_closed = 'No linked tickets';

jQuery('#linked_tickets_widget .heading').text(h3_open);

jQuery('#linked_tickets_widget').removeClass('inactive');

jQuery(element_custom_field_parent).val('');

jQuery(element_custom_field_parent).closest('.field').show();

jQuery('.linked_tickets_new').show().html(this_object.ticketCreateNew(value_custom_field_parent, "Create new child ticket with the following requester:"));

this_object.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "parent_ticket_id_359268": "" } } }', true);

}

} else {

// Current ticket is a Child

h3_open = 'Parent and Siblings:';

h3_closed = 'This is a Child ticket';

jQuery('#linked_tickets_widget .heading').text(h3_open);

jQuery('#linked_tickets_widget').removeClass('inactive');

jQuery(element_custom_field_parent).closest('.field').show();

jQuery('.linked_tickets_new').show().html(this_object.ticketCreateNew(value_custom_field_parent, "Create new sibling ticket with the following requester:"));

this_object.ticketAjaxCallGetParent(value_custom_field_parent);

}

} else {

// Current ticket is Not linked

h3_open = 'No linked tickets';

h3_closed = 'No linked tickets';

jQuery('#linked_tickets_widget .heading').text(h3_open);

jQuery('#linked_tickets_widget').removeClass('inactive');

jQuery(element_custom_field_parent).closest('.field').show();

jQuery('.linked_tickets_new').show().html(this_object.ticketCreateNew('{{ticket.id}}', "Create new child ticket with the following requester:"));

if (value_custom_field_children) {

// Error: Current ticket has siblings but no parent => Has no siblings

jQuery(element_custom_field_children).val('');

this_object.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "child_ticket_id_359268": "" } } }', false);

}

}

},



ticketCreateNew: function(parent_ticket_id, table_caption) {

var newTicketCreate = '',

tmp1 = '',

tmp2 = '',

new1 = '',

new2 = '',

new3 = '',

new4 = '';

var tmpName = '',

tmpEmail = '';

tmpName = DataStore.store.current_user.user.name;

tmpEmail = DataStore.store.current_user.user.email;

if (tmpEmail.length > 0) {

tmp1 = encodeURI("/helpdesk/tickets/compose_email?parent=" + parent_ticket_id + "&requester_name=" + tmpName + "&requester_email=" + tmpEmail);

tmp2 = encodeURI("/helpdesk/tickets/new?parent=" + parent_ticket_id + "&requester_name=" + tmpName + "&requester_email=" + tmpEmail);

new1 = "<td id=\"td_new1\"><a href=\"" + tmp1 + "\" target=\"_blank\" title=' New Email - " + escapeHtml(tmpName) + " ' style=\"color: #ccf\">@</a>&nbsp;<a href=\"" + tmp2 + "\" target=\"_blank\" title=' New Ticket - " + escapeHtml(tmpName) + " '>Me</a></td>";

}

tmpName = jQuery(element_responder_id).text();

new2 = "<td id=\"td_new2\"><span style=\"color: #fff\">Current Agent</span></td>";

if (jQuery(element_responder_id).val()) {

tmp2 = encodeURI("/helpdesk/tickets/new?parent=" + parent_ticket_id + "&requester_name=" + "Agent: " + tmpName + "&requester_id=" + jQuery(element_responder_id).val());

new2 = "<td id=\"td_new2\"><a href=\"" + tmp2 + "\" target=\"_blank\" title=' New Ticket - " + escapeHtml(tmpName) + " '>Current Agent</a></td>";

}

tmpName = "{{ticket.requester.name}}";

tmpEmail = "{{ticket.requester.email}}";

if (tmpEmail.length > 0) {

tmp1 = encodeURI("/helpdesk/tickets/compose_email?parent=" + parent_ticket_id + "&requester_name=" + tmpName + "&requester_email=" + tmpEmail);

tmp2 = encodeURI("/helpdesk/tickets/new?parent=" + parent_ticket_id + "&requester_name=" + tmpName + "&requester_email=" + tmpEmail);

new3 = "<td id=\"td_new3\"><a href=\"" + tmp1 + "\" target=\"_blank\" title=' New Email - " + escapeHtml(tmpName) + " <" + tmpEmail + "> ' style=\"color: #ccf\">@</a>&nbsp;<a href=\"" + tmp2 + "\" target=\"_blank\" title=' New Ticket - " + escapeHtml(tmpName) + " <" + tmpEmail + "> '>Current Requester</a></td>";

} else {

tmp1 = encodeURI("/helpdesk/tickets/compose_email?parent=" + parent_ticket_id + "&requester_name=" + tmpName + "&requester_id={{requester.id}}");

tmp2 = encodeURI("/helpdesk/tickets/new?parent=" + parent_ticket_id + "&requester_name=" + tmpName + "&requester_id={{requester.id}}");

new3 = "<td id=\"td_new3\"><span style=\"color: #fff\">@</span>&nbsp;<a href=\"" + tmp2 + "\" target=\"_blank\" title=' New Ticket - " + escapeHtml(tmpName) + " '>Current Requester</a></td>";

}

new4 = "<td id=\"td_new4\"><a href=\"/helpdesk/tickets/new?parent=" + parent_ticket_id + "\" target=\"_blank\" title=\" New Email - Other requester \" style=\"color: #ccf\">@</a>&nbsp;<a href=\"/helpdesk/tickets/new?parent=" + parent_ticket_id + "\" target=\"_blank\" title=\" New Ticket - Other requester \">Other</a></td>";

var newTicketCreate = "<table><caption>" + table_caption + "</caption><tbody><tr>" +

new2 + new1 + new3 + new4 + "</tr></tbody></table>";

return newTicketCreate;

},



getAgentCurrent: function() {

var value_custom_field_parent = jQuery(element_custom_field_parent).val();

var tmp2 = '',

new2 = '';

var tmpName = '';

tmpName = jQuery(element_responder_id).text();

new2 = "<span style=\"color: #fff\">Current Agent</span>";

if (jQuery(element_responder_id).val()) {

tmp2 = encodeURI("/helpdesk/tickets/new?parent=" + value_custom_field_parent + "&requester_name=" + "Agent: " + tmpName + "&requester_id=" + jQuery(element_responder_id).val());

new2 = "<a href=\"" + tmp2 + "\" target=\"_blank\" title=' New Ticket - " + escapeHtml(tmpName) + " '>Current Agent</a>";

}

jQuery('#td_new2').html(new2);

},



ticketAjaxCallGetParent: function(ticket_id_parent) {

var this_object = this;

var value_custom_field_children = jQuery(element_custom_field_children).val();

var timeoptions = {

weekday: "short",

year: "numeric",

month: "short",

day: "numeric",

hour: "numeric",

minute: "numeric"

};

jQuery.ajax({

type: 'GET',

url: '/helpdesk/tickets/' + ticket_id_parent + '.json',

contentType: 'application/json',

dataType: 'json',

success: function(data) {

var children_arr = [];

var proper_value_custom_field_children = '';



if ((data.helpdesk_ticket.custom_field.parent_ticket_id_359268) && (data.helpdesk_ticket.custom_field.parent_ticket_id_359268 != ticket_id_parent)) {

jQuery(element_custom_field_parent).val(data.helpdesk_ticket.custom_field.parent_ticket_id_359268);

this_object.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "parent_ticket_id_359268": "' + data.helpdesk_ticket.custom_field.parent_ticket_id_359268 + '" } } }', true);

} else {

proper_value_custom_field_children = this_object.listFilter(data.helpdesk_ticket.custom_field.child_ticket_id_359268, '{{ticket.id}}', ticket_id_parent);

children_arr = proper_value_custom_field_children.split(',');



if (!data.helpdesk_ticket.custom_field.parent_ticket_id_359268) {

// Warning: Our parent does not know that he is a parent => Our parent is updated

this_object.ticketAjaxCallPut(ticket_id_parent, '{ "helpdesk_ticket" : { "custom_field" : { "parent_ticket_id_359268": "' + ticket_id_parent + '", "child_ticket_id_359268": "' + proper_value_custom_field_children + '" } } }', false);

} else {

if (data.helpdesk_ticket.custom_field.child_ticket_id_359268 != proper_value_custom_field_children) {

// Warning: Our parent has a different list of children => Our parent is updated

this_object.ticketAjaxCallPut(ticket_id_parent, '{ "helpdesk_ticket" : { "custom_field" : { "child_ticket_id_359268": "' + proper_value_custom_field_children + '" } } }', false);

}

}



if (value_custom_field_children != proper_value_custom_field_children) {

// Warning: Current ticket has a different list of children => Current ticket is updated

jQuery(element_custom_field_children).val(proper_value_custom_field_children);

this_object.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "child_ticket_id_359268": "' + proper_value_custom_field_children + '" } } }', false);

}



this_object.ticketPrint(data.helpdesk_ticket, true);



jQuery.each(children_arr, function(index, item) {

if (item != '{{ticket.id}}') {

this_object.ticketAjaxCallGetChild(item, ticket_id_parent);

}

});

}

},

statusCode: {

404: function() {

// Error: Parent [ ticket_id_parent ] does not exist (404)

h3_open = 'No linked tickets';

h3_closed = 'No linked tickets';

jQuery('#linked_tickets_widget .heading').text(h3_open);

jQuery('#linked_tickets_widget').removeClass('inactive');

jQuery(element_custom_field_parent).val('');

jQuery(element_custom_field_parent).closest('.field').show();

this_object.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "parent_ticket_id_359268": "" } } }', true);

}

}

});

},



ticketAjaxCallGetChild: function(ticket_id_child, ticket_id_parent) {

var this_object = this;

var timeoptions = {

weekday: "short",

year: "numeric",

month: "short",

day: "numeric",

hour: "numeric",

minute: "numeric"

};

jQuery.ajax({

type: 'GET',

url: '/helpdesk/tickets/' + ticket_id_child + '.json',

contentType: 'application/json',

dataType: 'json',

success: function(data) {

var value_custom_field_children = jQuery(element_custom_field_children).val();

var proper_value_custom_field_children = '';

if (data.helpdesk_ticket.custom_field.parent_ticket_id_359268 == ticket_id_parent) {

this_object.ticketPrint(data.helpdesk_ticket, false);

} else {

// Error: Child has a different parent => Remove child from our list of children

proper_value_custom_field_children = this_object.listFilter(value_custom_field_children, '', ticket_id_child);



jQuery(element_custom_field_children).val(proper_value_custom_field_children);

this_object.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "child_ticket_id_359268": "' + proper_value_custom_field_children + '" } } }', false);

if (ticket_id_parent != '{{ticket.id}}') {

this_object.ticketAjaxCallPut(ticket_id_parent, '{ "helpdesk_ticket" : { "custom_field" : { "child_ticket_id_359268": "' + proper_value_custom_field_children + '" } } }', false);

}

}

},

statusCode: {

404: function() {

var value_custom_field_children = jQuery(element_custom_field_children).val();

var proper_value_custom_field_children = '';

proper_value_custom_field_children = this_object.listFilter(value_custom_field_children, '', ticket_id_child);



jQuery(element_custom_field_children).val(proper_value_custom_field_children);

this_object.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "child_ticket_id_359268": "' + proper_value_custom_field_children + '" } } }', false);

if (ticket_id_parent != '{{ticket.id}}') {

this_object.ticketAjaxCallPut(ticket_id_parent, '{ "helpdesk_ticket" : { "custom_field" : { "child_ticket_id_359268": "' + proper_value_custom_field_children + '" } } }', false);

}

}

}

});

},



ticketAjaxCallPut: function(ticket_id, json_data, reload_widget) {

var this_object = this;

jQuery.ajax({

type: 'PUT',

url: '/helpdesk/tickets/' + ticket_id + '.json',

contentType: 'application/json',

dataType: 'json',

data: json_data,

success: function() {

if (reload_widget) {

linked_tickets.onSidebarLoaded();

}

}

});

},



ticketPrint: function(data_helpdesk_ticket, is_parent) {

var timeoptions = {

weekday: "short",

year: "numeric",

month: "short",

day: "2-digit",

hour: "numeric",

minute: "numeric"

};



time_created_at = new Date(data_helpdesk_ticket.created_at);

time_updated_at = new Date(data_helpdesk_ticket.updated_at);

var window_location_origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');

var parent_or_child_class = ' child';

var parent_or_child = '<div class="linked_ticket_child">Sibling</div>';

var value_custom_field_parent = jQuery(element_custom_field_parent).val();

if (is_parent) {

parent_or_child_class = ' parent'

parent_or_child = '<div class="linked_ticket_parent">Parent</div>';

} else {

if (value_custom_field_parent) {

if (value_custom_field_parent == '{{ticket.id}}') {

parent_or_child = '<div class="linked_ticket_child">Child</div>';

}

}

if (jQuery(element_custom_field_parent).val() == '{{ticket.id}}') {

if ((data_helpdesk_ticket.status != '4') && (data_helpdesk_ticket.status != '5')) {

jQuery('.tkt-details-sticky').css("background", "#ffffff linear-gradient(#ffffff, #ffffff, #ffddcc) repeat scroll 0 0");

}

}

}

var requester_name = '<span class="field_description" title=" Requester ">R:</span> <a target="user_' + data_helpdesk_ticket.requester_id + '" title=" See requester ' + data_helpdesk_ticket.requester_name + ' " href="' +

window_location_origin +

'/users/' +

data_helpdesk_ticket.requester_id + '">' + data_helpdesk_ticket.requester_name + '</a>';

var time_created_and_or_updated = '<br><span class="field_description" title=" Created ( local time ) ">C:</span> <span class="format_date">' +

time_created_at.toLocaleString("en-GB", timeoptions) + "</span>";

if (data_helpdesk_ticket.created_at != data_helpdesk_ticket.updated_at) {

var time_created_and_or_updated = '<br><span class="field_description" title=" Created ( local time ) ">C:</span> <span class="format_date">' +

time_created_at.toLocaleString("en-GB", timeoptions) +

'</span><br><span class="field_description" title=" Updated ( local time ) ">U:</span> <span class="format_date">' +

time_updated_at.toLocaleString("en-GB", timeoptions) + "</span>";

}

var group_name = '<br><span class="field_description" title=" Group ">G:</span> -';

if (data_helpdesk_ticket.group_id) {

group_name = '<br><span class="field_description" title=" Group ">G:</span> ' +

jQuery("#helpdesk_ticket_group_id option[value='" +

data_helpdesk_ticket.group_id +

"']").text();

}

var agent_name = data_helpdesk_ticket.responder_name;

if (agent_name == 'No Agent') {

agent_name = '<br><span class="field_description" title=" Agent ">A:</span> -';

} else {

agent_name = '<br><span class="field_description" title=" Agent ">A:</span> <a target="user_' + data_helpdesk_ticket.responder_id + '" title=" See agent ' + data_helpdesk_ticket.responder_name + ' " href="' +

window_location_origin +

'/users/' +

data_helpdesk_ticket.requester_id + '">' + data_helpdesk_ticket.responder_name + '</a>';

}



var childData = '<div class="linked_ticket' + parent_or_child_class + '">' +

'<div class="linked_ticket_subject">' +

'<a target="ticket_' + data_helpdesk_ticket.display_id + '" title=" See ticket ' + data_helpdesk_ticket.display_id + ' " href="' +

window_location_origin +

'/helpdesk/tickets/' +

data_helpdesk_ticket.display_id + '">' +

data_helpdesk_ticket.subject +

'</a>' +

'</div>' +

'<div class="linked_ticket_status_and_id">' +

'<div class="linked_ticket_id">' +

'<a target="ticket_' + data_helpdesk_ticket.display_id + '" title=" See ticket ' + data_helpdesk_ticket.display_id + ' " href="' +

window_location_origin +

'/helpdesk/tickets/' +

data_helpdesk_ticket.display_id + '">' +

data_helpdesk_ticket.display_id +

'</a>' +

'</div>' +

'<div class="linked_ticket_status id' + data_helpdesk_ticket.status + '">' +

data_helpdesk_ticket.status_name +

'</div>' +

parent_or_child +

'</div>' +

'<div class="linked_ticket_time_and_agent">' +

requester_name +

time_created_and_or_updated +

group_name +

agent_name +

'</div>' +

'</div>';

jQuery('.linked_tickets_list').show().append(childData);

},



onReload: function() {

var this_object = this;

jQuery.ajax({

type: 'GET',

url: '/helpdesk/tickets/{{ticket.id}}.json',

contentType: 'application/json',

dataType: 'json',

success: function(data) {

jQuery(element_custom_field_parent).val(data.helpdesk_ticket.custom_field.parent_ticket_id_359268);

jQuery(element_custom_field_children).val(data.helpdesk_ticket.custom_field.child_ticket_id_359268);

this_object.onSidebarLoaded();

}

});

},



listFilter: function(list_string, field_add, field_remove) {

var list_array = [];

var proper_list_string = '';

var seen = {};



if (list_string) {

list_array = list_string.split(',');

}

if (field_add) {

list_array.push(field_add);

}

list_array.sort(function(a, b) {

return a - b

});

jQuery.each(list_array, function(index, item) {

if (!seen[item]) {

seen[item] = true;

if (item != field_remove) {

proper_list_string = proper_list_string + ',' + item;

}

}

});

if (proper_list_string) {

proper_list_string = proper_list_string.substring(1);

}

return proper_list_string;

},



escapeHtml: function(str) {

var div = document.createElement('div');

div.appendChild(document.createTextNode(str));

return div.innerHTML;

}



}



jQuery('#linked_tickets_widget').parent().parent().hide();

var element_custom_field_parent_or_child_ticket = '#TicketProperties #helpdesk_ticket_custom_field_parent_or_child_ticket_359268'; // Compatibility

var element_custom_field_children = '#TicketProperties #helpdesk_ticket_custom_field_child_ticket_id_359268';

var element_custom_field_parent = '#TicketProperties #helpdesk_ticket_custom_field_parent_ticket_id_359268';

var element_responder_id = 'select#helpdesk_ticket_responder_id option:selected';

var store_element_custom_field_parent = '#linked_tickets_widget .store_class_parent';

var store_element_responder_id = '#linked_tickets_widget .store_class_responder_id';



var h3_open = '';

var h3_closed = '';



var linked_tickets = new LinkedTickets();





jQuery(document).on("sidebar_loaded", function(event, data) {

linked_tickets.onSidebarLoaded();



setTimeout(function() { // This ensures backwards compatibility with existing App

var value_custom_field_parent_or_child_ticket = jQuery(element_custom_field_parent_or_child_ticket).val();

var proper_value_custom_field_parent_or_child_ticket = '';

var value_custom_field_children = jQuery(element_custom_field_children).val();

var value_custom_field_parent = jQuery(element_custom_field_parent).val();

if (value_custom_field_parent == '{{ticket.id}}') {

proper_value_custom_field_parent_or_child_ticket = 'Parent';

} else {

if (value_custom_field_parent) {

proper_value_custom_field_parent_or_child_ticket = 'Child';

}

}

if (value_custom_field_parent_or_child_ticket != proper_value_custom_field_parent_or_child_ticket) {

jQuery(element_custom_field_parent_or_child_ticket).val(proper_value_custom_field_parent_or_child_ticket);

linked_tickets.ticketAjaxCallPut('{{ticket.id}}', '{ "helpdesk_ticket" : { "custom_field" : { "parent_or_child_ticket_359268": "' + proper_value_custom_field_parent_or_child_ticket + '" } } }', false);

}

}, 3000);



});



jQuery('#linked_tickets_widget h3').on('click', function(ev, data) {

if (jQuery('#linked_tickets_widget').hasClass('inactive')) {

// Show

jQuery('.linked_tickets_list').show();

jQuery('.linked_tickets_new').show();

jQuery('.linked_tickets_new_agents').show();

jQuery('#linked_tickets_widget .heading').text(h3_open);

} else {

// Hide

jQuery('.linked_tickets_list').hide();




New ticket has parent
<style>

.ticket_section {

border: 1px solid #eee;

border-radius: 0 10px 10px;

margin: 0 0 10px 20px;

padding: 0 20px;

}

</style>

<script type="text/javascript">

(function($) {

var CloneParentTicket = Class.create();

CloneParentTicket.prototype = {



initialize: function() {

//

},



onDocumentReady: function() {

var this_object = this;

this_object.ticketAjaxCallGetParent(QueryString.parent);

},



ticketAjaxCallGetParent: function(ticket_id_parent) {

var this_object = this;

var path = window.location.pathname.substring(1);

var path_split = path.split("/");

var path_last_element = path_split[path_split.length - 1];

var requester_full = '';

if (path_last_element == 'new') {

// New ticket - Rearrange page

jQuery('li.default_description').insertAfter('li.default_subject');

jQuery('li.default_group').insertAfter('li.default_requester');

jQuery('li.default_agent').insertAfter('li.default_group');

jQuery('li.default_status').insertAfter('li.default_description');

jQuery('li.default_priority').insertAfter('li.default_status');

}

// Requester has email

if (QueryString.requester_email) {

if (QueryString.requester_name) {

requester_full = '"' + QueryString.requester_name + '" <' + QueryString.requester_email + '>';

} else {

requester_full = QueryString.requester_email;

}

jQuery('input#helpdesk_ticket_email').val(requester_full);

} else if (QueryString.requester_id) {

if (path_last_element == 'new') {

if (QueryString.requester_name) {

requester_full = '"' + QueryString.requester_name + '"';

}

jQuery('input#helpdesk_ticket_email').val(requester_full);

jQuery('input#helpdesk_ticket_email').data("requesterCheck", true);

jQuery('input#helpdesk_ticket_requester_id').val(QueryString.requester_id);

}

}

jQuery.ajax({

type: 'GET',

url: '/helpdesk/tickets/' + ticket_id_parent + '.json',

contentType: 'application/json',

dataType: 'json',

success: function(data) {

// Type

if (data.helpdesk_ticket.ticket_type) {

jQuery('#helpdesk_ticket_ticket_type').val(data.helpdesk_ticket.ticket_type);

jQuery('#s2id_helpdesk_ticket_ticket_type span.select2-chosen').html(jQuery('#helpdesk_ticket_ticket_type option:selected').text());

var t = jQuery('#helpdesk_ticket_ticket_type option:selected').data("id");

jQuery("ul.ticket_section").remove();

var e = jQuery("#picklist_section_" + t).parent();

0 != e.length && e.append(jQuery("#picklist_section_" + t).val().replace(new RegExp("&lt", "g"), "<").replace(new RegExp("&gt", "g"), ">")), jQuery("#helpdesk_ticket_status").trigger("change")

}

// Custom fields

var element1_id = '',

element2_id = '';

var element1_obj = new Object(),

element2_obj = new Object();

for (var prop in data.helpdesk_ticket.custom_field) {

// skip loop if the property is from prototype

if (!data.helpdesk_ticket.custom_field.hasOwnProperty(prop)) continue;

if (prop) {

element1_id = '#helpdesk_ticket_custom_field_' + prop;

element1_obj = jQuery(element1_id);

if (element1_obj.is('input:checkbox')) {

element1_obj.parent().parent().hide();

if (data.helpdesk_ticket.custom_field[prop]) {

element1_obj.prop('checked', true);

}

} else if (element1_obj.is('input')) {

element1_obj.parent().hide();

if (data.helpdesk_ticket.custom_field[prop]) {

element1_obj.val(data.helpdesk_ticket.custom_field[prop]);

}

} else if (element1_obj.is('select')) {

element1_obj.parent().hide();

if (data.helpdesk_ticket.custom_field[prop]) {

element1_obj.val(data.helpdesk_ticket.custom_field[prop]);

element2_id = '#s2id_helpdesk_ticket_custom_field_' + prop + ' span.select2-chosen';

element2_obj = jQuery(element2_id);

element2_obj.html(data.helpdesk_ticket.custom_field[prop]);

}

} else {

if (data.helpdesk_ticket.custom_field[prop]) {

jQuery('.compose-new-ticket').append('<li class="text custom_text field"><label for="helpdesk_ticket_custom_field_' + prop + '" class="">' + prop + '</label><input type="text" class="text" id="' + element1_id.substr(1) + '" name="helpdesk_ticket[custom_field][' + prop + ']" size="30" value="' + data.helpdesk_ticket.custom_field[prop] + '"></li>');

element1_obj = jQuery(element1_id);

element1_obj.parent().hide();

}

}

}

}

// Parent

jQuery('#helpdesk_ticket_custom_field_parent_ticket_id_359268').val(ticket_id_parent);

// Subject

if (data.helpdesk_ticket.subject) {

if (path_last_element == 'new') {

jQuery('#helpdesk_ticket_subject').replaceWith('<input type="text" size="30" name="helpdesk_ticket[subject]" id="helpdesk_ticket_subject" class="required text valid" aria-required="true" aria-invalid="false" value="' + data.helpdesk_ticket.subject + '">');

} else if (path_last_element == 'compose_email') {

jQuery('#helpdesk_ticket_subject').replaceWith('<input type="text" size="30" placeholder="Type email subject" name="helpdesk_ticket[subject]" id="helpdesk_ticket_subject" class="required text ticket-subject" aria-required="true" value="' + data.helpdesk_ticket.subject + '">');

}

}

// Priority

if (data.helpdesk_ticket.priority) {

jQuery('#helpdesk_ticket_priority').val(data.helpdesk_ticket.priority);

jQuery('#s2id_helpdesk_ticket_priority span.select2-chosen').html(jQuery('#helpdesk_ticket_priority option:selected').text());

}

// Description

if (data.helpdesk_ticket.description_html) {

if (path_last_element == 'new') {

jQuery('.redactor_editor').prepend(data.helpdesk_ticket.description_html);

} else if (path_last_element == 'compose_email') {

jQuery('.redactor_editor').prepend('<p><br><br></p><div class="freshdesk_quote"><blockquote class="freshdesk_quote" style="display: block;">' + data.helpdesk_ticket.description_html + '</blockquote></div>');

}

}

// Tags

var tag_li = '';

tag_input = '';

if (data.helpdesk_ticket.tags.length > 0) {

for (var i = 0; i < data.helpdesk_ticket.tags.length; i++) {

tag_input = tag_input + ',' + data.helpdesk_ticket.tags[i].name;

tag_li = tag_li + '<li class="select2-search-choice"><div>' + data.helpdesk_ticket.tags[i].name + '</div><a tabindex="-1" class="select2-search-choice-close" href="#"></a></li>';

}

jQuery('#s2id_helpdesk_ticket_tags_input ul.select2-choices').prepend(tag_li);

jQuery('#helpdesk_ticket_tags_input').val(tag_input.substring(1));

}

// Agent

if (data.helpdesk_ticket.responder_id) {

jQuery('#helpdesk_ticket_responder_id').val(data.helpdesk_ticket.responder_id);

jQuery('#s2id_helpdesk_ticket_responder_id span.select2-chosen').html(data.helpdesk_ticket.responder_name);

setTimeout(function() {

if (data.helpdesk_ticket.group_id) {

jQuery('#helpdesk_ticket_responder_id').val(data.helpdesk_ticket.responder_id);

jQuery('#s2id_helpdesk_ticket_responder_id span.select2-chosen').html(data.helpdesk_ticket.responder_name);

}

}, 500);

setTimeout(function() {

if (data.helpdesk_ticket.group_id) {

jQuery('#helpdesk_ticket_responder_id').val(data.helpdesk_ticket.responder_id);

jQuery('#s2id_helpdesk_ticket_responder_id span.select2-chosen').html(data.helpdesk_ticket.responder_name);

}

}, 1000);

setTimeout(function() {

if (data.helpdesk_ticket.group_id) {

jQuery('#helpdesk_ticket_responder_id').val(data.helpdesk_ticket.responder_id);

jQuery('#s2id_helpdesk_ticket_responder_id span.select2-chosen').html(data.helpdesk_ticket.responder_name);

}

jQuery('#cover_the_screen').remove();

}, 1500);

} else {

jQuery('#cover_the_screen').remove();

}

// Group

jQuery('#helpdesk_ticket_group_id').val(data.helpdesk_ticket.group_id);

jQuery('#s2id_helpdesk_ticket_group_id span.select2-chosen').html(jQuery('#helpdesk_ticket_group_id option:selected').text());

},

statusCode: {

404: function() {

console.log('function ------ ticketAjaxCallGetParent failure [' + ticket_id_parent + ']');

console.log('Error: Parent [' + ticket_id_parent + '] does not exist (404)');

alert('Error: Parent [' + ticket_id_parent + '] does not exist (404)');

}

}

});

}



}



var QueryString = function() {

// This function is anonymous, is executed immediately and

// the return value is assigned to QueryString!

var query_string = {};

var query = window.location.search.substring(1);

var vars = query.split("&");

for (var i = 0; i < vars.length; i++) {

var pair = vars[i].split("=");

// If first entry with this name

if (typeof query_string[pair[0]] === "undefined") {

query_string[pair[0]] = decodeURIComponent(pair[1]);

// If second entry with this name

} else if (typeof query_string[pair[0]] === "string") {

var arr = [query_string[pair[0]], decodeURIComponent(pair[1])];

query_string[pair[0]] = arr;

// If third or later entry with this name

} else {

query_string[pair[0]].push(decodeURIComponent(pair[1]));

}

}

return query_string;

}();



if (QueryString.parent) {

jQuery("body").prepend('<div id="cover_the_screen" style="opacity:0.7; background-color:#ccc; position:fixed; width:100%; height:100%; top:0px; left:0px; z-index:1000;"></div>');

};



var clone_parent_ticket = new CloneParentTicket();



jQuery(document).ready(function(event, data) {

// Check the URL for arguments

if (QueryString.parent) {

clone_parent_ticket.onDocumentReady();

}

});



})(jQuery);

</script>


 






And an ABSOLUTELY NECESSARY step I forgot to mention in the instructions:

Edit the source of BOTH apps and replace all occurrences of 359268 with the number of your own Freshdesk instance ID ( browse the HTML source of a ticket page to identify it ). If you don't do this, before you save the apps, they will not work.

 






I installed this ok but can only see one child ticket tied to a parent.  I cannot see multiple children tied to the same parent.






Thoughts?




Dear David,

changes ( added/removed linked tickets ) show when the user reloads the ticket page ( or clicks the small reload symbol ↻ at the top right of the app header ).

Also, please make sure that the type of the Child Ticket ID field is Single Line Text ( it cannot be Number  ).


Untitled.png










Thank you very much for this add on; it is much better than the one you referred to earlier!






It looks very nice and fits the purpose very well.



My 2 cents: the Parent or Child field is unnecessary; and the Parent Child custom app can be removed when we use this., which is certainly better.






Many thanks for sharing!






Hi Thanos! Really like your work here. Do you work on custom app requests (paid)?




Thanks Manan. No, I just made that for our company.

 




@Apiccioni

You are right. I just wanted the app to be compatible with the app that Freshdesk provides to the point of being able switch back to the Freshdesk app if need be. That is why that field was retained.






@Thanos: Got it! Thanks anyways :)
Btw, do you know of any developer communities which are freshdesk specific where I can look for some developers?




You can contact Freshdesk themselves. They do some custom app development and they also have developer partners that they can suggest.

 






Thanks @Thanos... let me reach out to them.






How do you find your instance id?




There now is an elegant way to do it by referencing window.current_account_id, as Freshdesk calls it ( but I don't have the time to make changes to the code above ).

To find out your account ID please install this custom app ( and enable it for Ticket detail page ). Then, just view a ticket and you will see the ID at the bottom of the right sidebar.

 



<div id="current_account_id">Freshdesk Account ID is xxxxxx</div>

<script type="text/javascript">

function print_current_account_id() {

console.log('window.current_account_id ' + window.current_account_id + ']');

jQuery('#current_account_id').html('Freshdesk Account ID is <b>' + window.current_account_id + '</b>');

}

jQuery(document).on('ticket_view_loaded', print_current_account_id);

</script>


 



 





 






@Manan: We have developers who can perform custom app development assignments.



Feel free to write me with any requests at marcus.landgren [@] swedbyte.se









Can anyone point me to some instructions on how to get this to work? I have saved off the code to a text file, replaced the ID and saved it as a Zip file. I keep getting an error:








  • Please correct the following errors 


  • Upload a valid Package (.zip) File







I have attempted to setup this custom app, but I keep receiving an error. I saved off the code for the custom apps, updated the ID, saved them as text files then zipped them.








  • Please correct the following errors 


  • Upload a valid Package (.zip) File