├── .gitignore
├── assets
├── logo.png
├── banner.png
├── logo-small.png
├── screenshot-1.png
├── screenshot-2.png
├── screenshot-3.png
├── logo-promotion.png
├── icon_nav_bar_active.png
├── icon_nav_bar_hover.png
└── icon_nav_bar_inactive.png
├── manifest.json
├── templates
├── layout.hdbs
├── ticket_filter_string.hdbs
├── main.hdbs
├── _tickets_export.hdbs
├── topic_options.hdbs
├── results.hdbs
└── ticket_options.hdbs
├── README.md
├── app.css
├── translations
└── en.json
├── LICENSE
└── app.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /tmp
2 |
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/logo.png
--------------------------------------------------------------------------------
/assets/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/banner.png
--------------------------------------------------------------------------------
/assets/logo-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/logo-small.png
--------------------------------------------------------------------------------
/assets/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/screenshot-1.png
--------------------------------------------------------------------------------
/assets/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/screenshot-2.png
--------------------------------------------------------------------------------
/assets/screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/screenshot-3.png
--------------------------------------------------------------------------------
/assets/logo-promotion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/logo-promotion.png
--------------------------------------------------------------------------------
/assets/icon_nav_bar_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/icon_nav_bar_active.png
--------------------------------------------------------------------------------
/assets/icon_nav_bar_hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/icon_nav_bar_hover.png
--------------------------------------------------------------------------------
/assets/icon_nav_bar_inactive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zendesk/advanced_search/master/assets/icon_nav_bar_inactive.png
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Advanced Search",
3 | "author": {
4 | "name": "Joe McCarron",
5 | "email": "success_apps@zendesk.com",
6 | "url": "https://github.com/jstjoe"
7 | },
8 | "defaultLocale": "en",
9 | "private": false,
10 | "location": "nav_bar",
11 | "version": "0.10.2",
12 | "frameworkVersion": "1.0"
13 | }
14 |
--------------------------------------------------------------------------------
/templates/layout.hdbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{setting "name"}}
4 |
5 |
6 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ⚠️ Use of this software is subject to important terms and conditions as set forth in the License file ⚠️
2 |
3 | # Advanced Search for Zendesk
4 |
5 | ## Description:
6 |
7 | Beta app designed to provide a GUI for search filter keywords, as well as export of search results to CSV (via data URIs)
8 |
9 | ## Screenshot(s):
10 | 
11 |
--------------------------------------------------------------------------------
/app.css:
--------------------------------------------------------------------------------
1 | input {
2 | border: 1px solid #d3d3d3;
3 | }
4 | /*.ticket_options label {
5 | display: block;
6 | }*/
7 | .column input {
8 | width: 400px;
9 | margin-bottom: 10px;
10 | }
11 | .column_1 {
12 | float: left;
13 | margin-right: 20px;
14 | }
15 |
16 | .results-well {
17 | overflow: scroll;
18 | }
19 | .no_wrap {
20 | white-space: nowrap;
21 | }
22 |
23 | input[type="checkbox"] {
24 | vertical-align: middle;
25 | margin-bottom: 4px;
26 | }
27 |
28 | a.pull-right {
29 | margin-top: 10px;
30 | }
31 |
32 | a.pull-right.btn {
33 | margin-top: 0px;
34 | }
35 |
--------------------------------------------------------------------------------
/templates/ticket_filter_string.hdbs:
--------------------------------------------------------------------------------
1 | {{#filters}}{{#if status}} status{{{status}}}{{/if}}{{#if ticket_type}} ticket_type:{{ticket_type}}{{/if}}{{#if priority}} priority{{{priority}}}{{/if}}{{#if date}} {{{date}}}{{/if}}{{#if group}} group:"{{group}}"{{/if}}{{#if assignee}} assignee:"{{assignee}}"{{/if}}{{#if submitter}} submitter:"{{submitter}}"{{/if}}{{#if organization}} organization:"{{organization}}"{{/if}}{{#if requester}} requester:"{{requester}}"{{/if}}{{#if commenter}} commenter:"{{commenter}}"{{/if}}{{#if cc}} cc:"{{cc}}"{{/if}}{{#if subject}} subject:"{{subject}}"{{/if}}{{#if description}} description:"{{description}}"{{/if}}{{#if tags}} tags:"{{tags}}"{{/if}}{{#if via}} via:{{via}}{{/if}}{{/filters}}
2 |
--------------------------------------------------------------------------------
/translations/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": {
3 | "package": "app_name",
4 | "description": {
5 | "value": "Play the famous zen tunes in your help desk.",
6 | "title": "app description"
7 | },
8 | "name": {
9 | "value": "Buddha Machine",
10 | "title": "app name"
11 | }
12 | },
13 |
14 | "loading": {
15 | "value": "Welcome to this Sample App",
16 | "title": "loading placeholder"
17 | },
18 |
19 | "fetch": {
20 | "done": {
21 | "value": "Good",
22 | "title": "fetch success"
23 | },
24 | "fail": {
25 | "value": "failed to fecth information from the server",
26 | "title": "fetch failure"
27 | }
28 | },
29 |
30 | "id": {
31 | "value": "ID",
32 | "title": "user id"
33 | },
34 |
35 | "email": {
36 | "value": "Email",
37 | "title": "user email"
38 | },
39 |
40 | "name": {
41 | "value": "Name",
42 | "title": "user name"
43 | },
44 |
45 | "role": {
46 | "value": "Role",
47 | "title": "user role"
48 | },
49 |
50 | "groups": {
51 | "value": "Groups",
52 | "title": "user groups"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/templates/main.hdbs:
--------------------------------------------------------------------------------
1 |
2 |
37 |
38 |
39 | {{!-- inject options here --}}
40 |
41 |
42 | {{!-- inject results here --}}
43 |
44 |
45 |
{{spinner "dotted"}}
46 |
This query has no results. Try broadening your search.
47 |
48 |
--------------------------------------------------------------------------------
/templates/_tickets_export.hdbs:
--------------------------------------------------------------------------------
1 | id{{#if columns.subject}},Subject{{/if}}{{#if columns.requester}},"Requester Name"{{/if}}{{#if columns.requester_email}},"Requester Email"{{/if}}{{#if columns.group}},Group{{/if}}{{#if columns.assignee}},"Assignee Name"{{/if}}{{#if columns.assignee_email}},"Assignee Email"{{/if}}{{#if columns.status}},Status{{/if}}{{#if columns.type}},Type{{/if}}{{#if columns.priority}},Priority{{/if}}{{#if columns.created_at}},Created{{/if}}{{#if columns.updated_at}},Updated{{/if}}{{#if columns.external_id}},External_ID{{/if}}{{#if columns.channel}},Channel{{/if}}{{#if columns.description}},Description{{/if}}{{#if columns.recipient}},Recipient{{/if}}{{#if columns.submitter}},Submitter{{/if}}{{#if columns.organization}},Organization{{/if}}{{#if columns.collaborators}},CCs{{/if}}{{#if columns.forum_topic}},Topic{{/if}}{{#if columns.problem_id}},Problem{{/if}}{{#if columns.has_incidents}},Incidents{{/if}}{{#if columns.tags}},Tags{{/if}}{{#each columns.customFields}},{{title}}{{/each}}
2 | {{#tickets}}{{id}}{{#if ../columns.subject}},"{{{subject}}}"{{/if}}{{#if ../columns.requester}},"{{requester}}"{{/if}}{{#if ../columns.requester_email}},"{{requester_email}}"{{/if}}{{#if ../columns.group}},{{group_id}}{{/if}}{{#if ../columns.assignee}},{{assignee}}{{/if}}{{#if ../columns.assignee_email}},{{assignee_email}}{{/if}}{{#if ../columns.status}},{{status}}{{/if}}{{#if ../columns.type}},{{type}}{{/if}}{{#if ../columns.priority}},{{priority}}{{/if}}{{#if ../columns.created_at}},"{{created_at}}"{{/if}}{{#if ../columns.updated_at}},"{{updated_at}}"{{/if}}{{#if ../columns.external_id}},"{{external_id}}"{{/if}}{{#if ../columns.channel}},"{{channel}}"{{/if}}{{#if ../columns.description}},"{{{description}}}"{{/if}}{{#if ../columns.recipient}},"{{recipient}}"{{/if}}{{#if ../columns.submitter}},"{{submitter}}"{{/if}}{{#if ../columns.submitter_email}},"{{submitter_email}}"{{/if}}{{#if ../columns.organization}},{{organization}}{{/if}}{{#if ../columns.collaborators}},"{{collaborators}}"{{/if}}{{#if ../columns.forum_topic}},{{forum_topic}}{{/if}}{{#if ../columns.problem_id}},{{problem_id}}{{/if}}{{#if ../columns.has_incidents}},{{has_incidents}}{{/if}}{{#if ../columns.tags}},"{{tags}}"{{/if}}{{#each custom_fields}},"{{#if textarea}}{{{value}}}{{else}}{{value}}{{/if}}"{{/each}}
3 | {{/tickets}}
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2013 Zendesk
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
15 | Capitalized terms used herein have the meaning set forth in the Zendesk, Inc.
16 | (“Zendesk”) Terms of Service (available at www.zendesk.com/company/terms) (the “Terms”).
17 | The software made available herein constitutes “ZendeskLabs Software” which may be
18 | implemented to enable features or functionality to be utilized in connection with a
19 | subscription to the Service.
20 | Notwithstanding anything to the contrary set forth in the Terms or any other
21 | agreement by and between you and Zendesk, ZendeskLabs Software is provided
22 | “AS IS” and on an “AS AVAILABLE” basis, and that Zendesk makes no warranty
23 | as to the ZendeskLabs Software.
24 |
25 | ZENDESK DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
26 | TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
27 | NONINFRINGEMENT AND THOSE ARISING FROM A COURSE OF DEALING OR USAGE OF TRADE
28 | RELATED TO THE ZENDESKLABS SOFTWARE, ITS USE OR ANY INABILITY TO USE IT OR
29 | THE RESULTS OF ITS USE.
30 |
31 | Use of ZendeskLabs Software is subject to the following risks and conditions:
32 | (i) the ZendeskLabs Software is not an component of the Service that
33 | has been designed for commercial release for by Zendesk;
34 |
35 | (ii) the ZendeskLabs Software may not be in final form and may contain errors,
36 | design flaws or other problems; (iii) the ZendeskLabs Software is not expected to
37 | function fully or adequately upon installation, and it is expected and anticipated that
38 | further testing, modification and development may be necessary to make the
39 | ZendeskLabs Software functional;
40 |
41 | (iv) it may not be possible to make the ZendeskLabs Software functional;
42 |
43 | (v) use of the ZendeskLabs Software may result in unexpected results, loss of data,
44 | project delays or other unpredictable damage or loss; and
45 |
46 | (vi) Zendesk is under no obligation to release and/or offer for sale commercial
47 | versions of the ZendeskLabs Software, and Zendesk has the right to unilaterally
48 | abandon development or availability of the ZendeskLabs Software at any time and
49 | without any obligation or liability to You. You further agree that Zendesk shall
50 | have no obligation to correct any bugs, defects or errors in the ZendeskLabs Software
51 | or otherwise to support or maintain the ZendeskLabs Software.
52 |
53 | If you elect to utilize any ZendeskLabs Software, you are agreeing to release Zendesk
54 | from any claim with regard to the ZendeskLabs Software, its operation, availability or
55 | its failure to operate or be available. Without limiting the generality of the foregoing,
56 |
57 | You acknowledge and agree that neither the use, availability nor operation of any
58 | ZendeskLabs Software shall be subject to any service level commitment applicable to the Service.
59 |
--------------------------------------------------------------------------------
/templates/topic_options.hdbs:
--------------------------------------------------------------------------------
1 | Status
2 |
3 |
4 | =
5 | >
6 | <
7 |
8 |
9 |
10 | new
11 | open
12 | pending
13 | on-hold
14 | solved
15 | closed
16 |
17 |
18 | Type
19 |
20 |
21 | question
22 | problem
23 | incident
24 | task
25 |
26 |
27 | Priority
28 |
29 |
30 | =
31 | >
32 | <
33 |
34 |
35 |
36 | urgent
37 | high
38 | normal
39 | low
40 |
41 |
42 | Date
43 |
44 |
45 | created
46 | updated
47 | solved
48 | due
49 |
50 | {{!-- this should be conditional on a date filter being selected above --}}
51 |
52 |
53 | =
54 | >
55 | <
56 |
57 |
58 |
59 |
60 | Group
61 |
62 |
63 |
64 | Assignee
65 |
66 |
67 | Submitter
68 |
69 |
70 |
71 | Organization
72 |
73 |
74 | Requester
75 |
76 |
77 |
78 | Commenter
79 |
80 |
81 | CC
82 |
83 |
84 |
85 | Subject
86 |
87 |
88 | Description
89 |
90 |
91 |
92 | Tags
93 |
94 |
95 | Via
96 |
97 |
98 | mail
99 | get_satisfaction
100 | dropbox
101 | twitter_dm
102 | twitter_fav
103 | twitter
104 | voicemail
105 | phone_call_inbound
106 | phone_call_outbound
107 | phone
108 | sms
109 | logmein
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/templates/results.hdbs:
--------------------------------------------------------------------------------
1 | {{#if exportEnabled}}{{/if}}
2 |
3 |
4 |
5 |
6 |
7 | {{!-- if result_type == ticket --}}
8 |
9 | {{#if columns.id}} ID {{/if}}
10 | {{#if columns.subject}}Subject {{/if}}
11 | {{#if columns.requester}}Requester Name {{/if}}
12 | {{#if columns.requester_email}}Requester Email {{/if}}
13 | {{#if columns.group}}Group {{/if}}
14 | {{#if columns.assignee}}Assignee Name {{/if}}
15 | {{#if columns.assignee_email}}Assignee Email {{/if}}
16 | {{#if columns.status}}Status {{/if}}
17 | {{#if columns.type}}Type {{/if}}
18 | {{#if columns.priority}}Priority {{/if}}
19 | {{#if columns.created_at}}Created {{/if}}
20 | {{#if columns.updated_at}}Updated {{/if}}
21 |
22 | {{#if columns.external_id}}External ID {{/if}}
23 | {{#if columns.channel}}Channel {{/if}}
24 | {{#if columns.description}}Description {{/if}}
25 | {{#if columns.recipient}}Recipient Address {{/if}}
26 | {{#if columns.submitter}}Submitter Name {{/if}}
27 | {{#if columns.submitter_email}}Submitter Email {{/if}}
28 | {{#if columns.organization}}Organization {{/if}}
29 | {{#if columns.collaborators}}CCs {{/if}}
30 | {{#if columns.forum_topic}}Linked Topic {{/if}}
31 | {{#if columns.problem_id}}Linked Problem {{/if}}
32 | {{#if columns.has_incidents}}Has Incidents? {{/if}}
33 | {{#if columns.tags}}Tags {{/if}}
34 |
35 | {{#each columns.customFields}}
36 | {{!-- prints the custom field's ID as a column --}}
37 | {{title}}
38 |
39 | {{/each}}
40 |
41 |
42 | {{!-- if topic --}}
43 |
44 | {{!-- if user --}}
45 |
46 | {{!-- if organization --}}
47 |
48 |
49 |
50 | {{#results}}
51 | {{!-- if ticket --}}
52 |
53 |
54 | {{#if ../columns.id}}
55 | {{id}}
56 | {{/if}}
57 | {{#if ../columns.subject}}
58 | {{subject}}
59 | {{/if}}
60 | {{#if ../columns.requester}}
61 | {{requester}}
62 | {{/if}}
63 | {{#if ../columns.requester_email}}
64 | {{requester_email}}
65 | {{/if}}
66 | {{#if ../columns.group}}
67 | {{group_id}}
68 | {{/if}}
69 | {{#if ../columns.assignee}}
70 | {{assignee}}
71 | {{/if}}
72 | {{#if ../columns.assignee_email}}
73 | {{assignee_email}}
74 | {{/if}}
75 | {{#if ../columns.status}}
76 | {{{status_label}}}
77 | {{/if}}
78 | {{#if ../columns.type}}
79 | {{#if type}}{{type}} {{/if}}
80 | {{/if}}
81 | {{#if ../columns.priority}}
82 | {{priority}}
83 | {{/if}}
84 | {{#if ../columns.created_at}}
85 | {{created_at}}
86 | {{/if}}
87 | {{#if ../columns.updated_at}}
88 | {{updated_at}}
89 | {{/if}}
90 |
91 | {{#if ../columns.external_id}}
92 | {{external_id}}
93 | {{/if}}
94 | {{#if ../columns.channel}}
95 | {{via.channel}}
96 | {{/if}}
97 | {{#if ../columns.description}}
98 | {{description}}
99 | {{/if}}
100 | {{#if ../columns.recipient}}
101 | {{recipient}}
102 | {{/if}}
103 | {{#if ../columns.submitter}}
104 | {{submitter}}
105 | {{/if}}
106 | {{#if ../columns.submitter_email}}
107 | {{submitter_email}}
108 | {{/if}}
109 | {{#if ../columns.organization}}
110 | {{organization_id}}
111 | {{/if}}
112 | {{#if ../columns.collaborators}}
113 | {{#each collaborators}}{{this.name}} {{#unless @last}}, {{/unless}}{{/each}}
114 | {{/if}}
115 | {{#if ../columns.forum_topic}}
116 | {{forum_topic}}
117 | {{/if}}
118 | {{#if ../columns.problem_id}}
119 | {{problem_id}}
120 | {{/if}}
121 | {{#if ../columns.has_incidents}}
122 | {{has_incidents}}
123 | {{/if}}
124 | {{#if ../columns.tags}}
125 | {{tags}}
126 | {{/if}}
127 |
128 | {{#if ../columns.customFields}}
129 | {{#each custom_fields}}
130 | {{!-- prints the custom fields as a column --}}
131 | {{value}}
132 | {{/each}}
133 | {{/if}}
134 |
135 |
136 | {{!-- if topic --}}
137 |
138 | {{!-- if user --}}
139 |
140 | {{!-- if organization --}}
141 | {{/results}}
142 |
143 |
144 |
145 | {{!-- pagination --}}
146 |
147 |
159 |
--------------------------------------------------------------------------------
/templates/ticket_options.hdbs:
--------------------------------------------------------------------------------
1 |
113 |
114 |
154 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | /*global Blob*/
2 | /*global URL*/
3 | /*global File*/
4 |
5 | (function() {
6 | return {
7 | // EVENTS =================================================================================================================
8 | events: {
9 | 'app.activated':'onAppActivated',
10 | 'pane.activated':'onPaneActivated',
11 | 'change select.type':'onTypeChanged',
12 | 'keyup input.user':'findUsers',
13 | // 'keyup input.string':'onTextEntered',
14 | // 'change select.dateType':'onDateTypeChanged',
15 | // 'change input.startDate':'onStartDateChanged',
16 | // 'change input.endDate':'onEndDateChanged',
17 | // 'change select.group':'onGroupChanged',
18 | // 'change select.assignee':'onAssigneeChanged',
19 | 'click button.addFilter':'onAddFilterClicked',
20 | 'click button.search':'onSearchClicked',
21 | 'click a.prev_page':'onPrevClicked',
22 | 'click a.next_page':'onNextClicked',
23 |
24 | // request events
25 | 'search.done':'onSearchComplete',
26 | // 'search.fail':'onSearchFail',
27 | 'getUrl.done':'onSearchComplete',
28 | 'getTicketFields.done':'setCustomFields'
29 | },
30 |
31 | // REQUESTS =================================================================================================================
32 | requests: {
33 | // searchIncremental: function(query, sort_by, sort_order, page) {
34 | // return {
35 | // url: helpers.fmt('/api/v2/search/incremental?query=%@&sort_by=%@&sort_order=%@&page=%@', query, sort_by, sort_order, page)
36 | // };
37 | // },
38 |
39 | autocompleteUsers: function(name) {
40 | return {
41 | url: '/api/v2/users/autocomplete.json?name=' + name
42 | };
43 | },
44 |
45 | search: function(query, sort_by, sort_order, page) {
46 | return {
47 | url: helpers.fmt('/api/v2/search.json?query=%@&sort_by=%@&sort_order=%@&page=%@', query, sort_by, sort_order, page)
48 | };
49 | },
50 |
51 | getUrl: function(url) {
52 | return {
53 | url: url
54 | };
55 | },
56 |
57 | getAssignees: function(page) {
58 | return {
59 | url: helpers.fmt('/api/v2/users.json?role[]=agent&role[]=admin&page=%@', page)
60 | };
61 | },
62 |
63 | getUsersBatch: function(userBatch) {
64 | var ids = userBatch.toString();
65 | return {
66 | url: '/api/v2/users/show_many.json?ids=' + ids
67 | };
68 | },
69 |
70 | getTicketFields: function(url) {
71 | if(!url) {url = '/api/v2/ticket_fields.json';}
72 | return {
73 | url: url
74 | };
75 | }
76 | },
77 |
78 | // EVENT CALLBACKS ==========================================================================================================
79 | onAppActivated: function() {
80 | if (File && Blob && URL) {
81 | // Browser is fully supportive for export
82 | this.exportEnabled = true;
83 | } else {
84 | // Browser not supported. Disable export
85 | this.exportEnabled = false;
86 | }
87 | },
88 |
89 | onPaneActivated: function(data) {
90 | if (data.firstLoad) {
91 | this.switchTo('main');
92 | this.$('span.loading').hide();
93 | this.$('span.no_results').hide();
94 | this.userIDs = [];
95 | this.users = [];
96 | this.ticketFields = [];
97 | this.customFields = [];
98 | this.columns = {};
99 | this.ajax('getTicketFields');
100 | }
101 | },
102 |
103 | onTypeChanged: function(e) {
104 | var type = e.currentTarget.value,
105 | options_html = '';
106 |
107 | switch (type) {
108 | case "ticket":
109 | options_html = this.renderTemplate("ticket_options", {
110 | customFields: this.customFields
111 | });
112 | break;
113 | case "topic":
114 | options_html = this.renderTemplate("topic_options");
115 | break;
116 | case "user":
117 | options_html = this.renderTemplate("user_options");
118 | break;
119 | case "organization":
120 | options_html = this.renderTemplate("organization_options");
121 | break;
122 | case "":
123 | options_html = "Choose a specific type to get access to additional filter options.";
124 | break;
125 | }
126 | //inject additional options
127 | this.$("div.type_options").html(options_html);
128 | // autocomplete ticket options
129 | var userFields = ["assignee","requester","submitter","cc","commenter"];
130 | _.each(userFields, function(title) {
131 | this.$('input.' + title).autocomplete({
132 | minLength: 0
133 | });
134 | }, this);
135 | },
136 |
137 | findUsers: function(e) {
138 | var name = e.currentTarget.value;
139 | var encodedQuery = encodeURIComponent(name);
140 | this.ajax('autocompleteUsers', encodedQuery).done(function(response) {
141 | var users = _.map(response.users, function(user) {
142 | return {
143 | label: user.name + " | " + user.email,
144 | value: user.email || user.id
145 | };
146 | });
147 |
148 | this.$('input#' + e.currentTarget.id).autocomplete({
149 | source: users
150 | });
151 | });
152 | },
153 |
154 | onAddFilterClicked: function(e) {
155 | if (e) {e.preventDefault();}
156 | // render various filters
157 | },
158 |
159 |
160 | onSearchClicked: function(e) {
161 | if (e) {e.preventDefault();}
162 | this.$('div.results').html('');
163 | var string = this.$('input.string').val(),
164 | type = this.$('form.main_search select.type').val();
165 | this.type = type;
166 | var filter_string = '';
167 | switch (type) {
168 | case "ticket"://if searching for tickets
169 | var status_operator = '';
170 | // TODO change to another switch
171 | if(this.$('form.ticket_filters select.status_operator').val() == 'greater') {
172 | status_operator = '>';
173 | } else if (this.$('form.ticket_filters select.status_operator').val() == 'less') {
174 | status_operator = '<';
175 | } else if (this.$('form.ticket_filters select.status_operator').val() == ':') {
176 | status_operator = ':';
177 | }
178 | var priority_operator = '';
179 | if(this.$('form.ticket_filters select.priority_operator').val() == 'greater') {
180 | priority_operator = '>';
181 | } else if (this.$('form.ticket_filters select.priority_operator').val() == 'less') {
182 | priority_operator = '<';
183 | } else if (this.$('form.ticket_filters select.priority_operator').val() == ':') {
184 | priority_operator = ':';
185 | }
186 | var date_operator = '';
187 | if(this.$('form.ticket_filters select.date_operator').val() == 'greater') {
188 | date_operator = '>';
189 | } else if (this.$('form.ticket_filters select.date_operator').val() == 'less') {
190 | date_operator = '<';
191 | } else if (this.$('form.ticket_filters select.date_operator').val() == ':') {
192 | date_operator = ':';
193 | }
194 | var ticket_filters = {
195 | "status": status_operator + this.$('form.ticket_filters select.status_value').val(),
196 | "ticket_type": this.$('form.ticket_filters select.ticket_type').val(),
197 | "priority": priority_operator + this.$('form.ticket_filters select.priority_value').val(),
198 | "date": this.$('form.ticket_filters select.date_type').val() + date_operator + this.$('form.ticket_filters input.date_value').val(),
199 | "group": this.$('form.ticket_filters input.group').val(),
200 | "assignee": this.$('form.ticket_filters input.assignee').val(),
201 | "submitter": this.$('form.ticket_filters input.submitter').val(),
202 | "organization": this.$('form.ticket_filters input.organization').val(),
203 | "requester": this.$('form.ticket_filters input.requester').val(),
204 | "commenter": this.$('form.ticket_filters input.commenter').val(),
205 | "cc": this.$('form.ticket_filters input.cc').val(),
206 | "subject": this.$('form.ticket_filters input.subject').val(),
207 | "description": this.$('form.ticket_filters input.description').val(),
208 | "tags": this.$('form.ticket_filters input.tags').val(), //.split(/\W/)
209 | "via": this.$('form.ticket_filters select.via').val()
210 | };
211 |
212 | // render a template to build the filters string
213 | filter_string = this.renderTemplate('ticket_filter_string', {
214 | filters: ticket_filters
215 | });
216 |
217 | this.columns = {
218 | type: this.$('form.ticket_columns .type').prop('checked'),
219 | id: this.$('form.ticket_columns .id').prop('checked'),
220 | subject: this.$('form.ticket_columns .subject').prop('checked'),
221 | group: this.$('form.ticket_columns .group').prop('checked'),
222 | assignee: this.$('form.ticket_columns .assignee').prop('checked'),
223 | assignee_email: this.$('form.ticket_columns .assignee_email').prop('checked'),
224 | requester: this.$('form.ticket_columns .requester').prop('checked'),
225 | requester_email: this.$('form.ticket_columns .requester_email').prop('checked'),
226 | status: this.$('form.ticket_columns .status').prop('checked'),
227 | priority: this.$('form.ticket_columns .priority').prop('checked'),
228 | created_at: this.$('form.ticket_columns .created').prop('checked'),
229 | updated_at: this.$('form.ticket_columns .updated').prop('checked'),
230 |
231 | external_id: this.$('form.ticket_columns .external_id').prop('checked'),
232 | channel: this.$('form.ticket_columns .channel').prop('checked'),
233 | description: this.$('form.ticket_columns .description').prop('checked'),
234 | recipient: this.$('form.ticket_columns .recipient').prop('checked'),
235 | submitter: this.$('form.ticket_columns .submitter').prop('checked'),
236 | submitter_email: this.$('form.ticket_columns .submitter_email').prop('checked'),
237 | organization: this.$('form.ticket_columns .organization').prop('checked'),
238 | collaborators: this.$('form.ticket_columns .collaborators').prop('checked'),
239 | forum_topic: this.$('form.ticket_columns .forum_topic').prop('checked'),
240 | problem_id: this.$('form.ticket_columns .problem_id').prop('checked'),
241 | has_incidents: this.$('form.ticket_columns .has_incidents').prop('checked'),
242 | tags: this.$('form.ticket_columns .tags').prop('checked'),
243 |
244 | customFields: this.selectCustomFields()
245 | };
246 | break;
247 | // TODO add cases for other objects
248 | } // end switch
249 |
250 | //no matter the type...
251 | this.results = [];
252 | var query = string + filter_string + ' type:' + type,
253 | sort_by = this.$('select.sort_by').val(),
254 | sort_order = this.$('select.sort_order').val(),
255 | page = '1';
256 | if(query.length < 2) {
257 | services.notify("A search query must have at least two characters.", "error");
258 | } else {
259 | var encodedQuery = encodeURIComponent(query);
260 | // store the query globally
261 | this.encodedQuery = encodedQuery;
262 | this.$("span.no_results").hide();
263 | this.$("span.loading").show();
264 | // make the request
265 | this.ajax('search', encodedQuery, sort_by, sort_order, page);
266 | }
267 | },
268 |
269 | onPrevClicked: function(e) {
270 | e.preventDefault();
271 | this.results = [];
272 | this.ajax('getUrl', this.prev_page);
273 | this.$('div.results').html('');
274 | this.$("span.loading").show();
275 | },
276 |
277 | onNextClicked: function(e) {
278 | e.preventDefault();
279 | this.results = [];
280 | this.ajax('getUrl', this.next_page);
281 | this.$('div.results').html('');
282 | this.$("span.loading").show();
283 | },
284 |
285 | // onFilterSelected: function(e) {
286 | // if (e) {e.preventDefault();}
287 | // //grab the selection and render the additional filter UI
288 | // //use a global variable to track the number of these filters rendered, and give them an ID to indicate?
289 | // },
290 |
291 | // REQUEST CALLBACKS ==========================================================================================================
292 | setCustomFields: function(ticket_fields) {
293 | this.ticketFields = this.ticketFields.concat(ticket_fields.ticket_fields);
294 |
295 | if (ticket_fields.next_page) {
296 | this.ajax('getTicketFields', ticket_fields.next_page);
297 | return;
298 | } else {
299 | this.customFields = _.filter(this.ticketFields, function(field) {
300 | return !_.contains(['subject', 'description', 'status', 'tickettype', 'priority', 'group', 'assignee'], field.type) && field.active;
301 | });
302 | var e = {"currentTarget": {"value": "ticket"}};
303 | this.onTypeChanged(e);
304 | }
305 | },
306 |
307 | // findOrgs: function() {
308 |
309 | // },
310 |
311 | // foundOrgs: function(response) {
312 | // var organizations = response.organizations;
313 |
314 | // },
315 |
316 | onSearchComplete: function(response) {
317 | var allPages = this.$('.all_pages').prop('checked');
318 | this.results = this.results.concat(response.results);
319 | var next_page,
320 | prev_page;
321 | if(allPages && response.next_page) {
322 | // get the next page by URL
323 | this.ajax('getUrl', response.next_page);
324 | return;
325 | } else {
326 | // TODO: add buttons # numbering
327 | if(response.next_page) {
328 | next_page = response.next_page;
329 | this.next_page = response.next_page;
330 | }
331 | if(response.previous_page) {
332 | prev_page = response.previous_page;
333 | this.prev_page = response.previous_page;
334 | }
335 | this.numberOfResults = response.count;
336 | }
337 | var results = this.results;
338 | if(results.length === 0) {
339 | this.$("span.loading").hide();
340 | this.$('span.no_results').show();
341 | return;
342 | }
343 | // TODO make conditional for results type - e.g. this.type == 'tickets'
344 | // massage the data...
345 | _.each(results, function(result, n) {
346 | // store user IDs
347 | var last;
348 | if(results.length == n+1) {last = true;}
349 | else {last = false;}
350 | var users = _.union(result.collaborator_ids, [result.assignee_id, result.requester_id, result.submitter_id]);
351 | this.addUsers(users, last);
352 | }.bind(this));
353 | },
354 |
355 | // HELPER METHODS ===========================================================================================================
356 |
357 | addUsers: function(ids, last) {
358 | _.each(ids, function(id) {
359 | this.userIDs.push(id);
360 | }.bind(this));
361 | this.userIDs = _.filter(_.uniq(this.userIDs), Boolean);
362 | if(this.userIDs.length >= 100 || last) {
363 | var userBatch = _.first(this.userIDs, 100);
364 | this.userIDs = _.rest(this.userIDs, 99);
365 | this.ajax('getUsersBatch', userBatch).done(function(response) {
366 | this.users = this.users.concat(response.users);
367 | _.defer(function(){
368 | this.encodeResults(this.results);
369 | }.bind(this));
370 | });
371 | }
372 | },
373 |
374 | selectCustomFields: function() {
375 | var that = this,
376 | customFields = this.customFields,
377 | selected = this.$('.custom_field_options input').map(function () {
378 | if( that.$(this).prop('checked') ) {
379 | return that.$(this).attr('data-field-option-id');
380 | }
381 | });
382 | selected = _.toArray(selected);
383 | var columns = _.filter(customFields, function(cf) {
384 | return _.contains(selected, cf.id.toString());
385 | });
386 | return columns;
387 | },
388 |
389 | encodeResults: function(results) {
390 | this.encoded = [];
391 | var custom_fields = this.columns.customFields;
392 | var cfIDs = _.map(custom_fields, function(cf) {
393 | return cf.id;
394 | });
395 | _.each(results, function(result, n) {
396 | // filter the custom field result set down to the selected columns
397 | result.custom_fields = _.filter(result.custom_fields, function(cf) {
398 | return _.contains(cfIDs, cf.id);
399 | });
400 | result.custom_fields = _.map(result.custom_fields, function(cf) {
401 | var field = _.find(custom_fields, function(f) { return f.id == cf.id; });
402 | // add flag to textarea fields (used in the template)
403 | if(field.type == 'textarea') {
404 | cf.textarea = true;
405 | }
406 | return cf;
407 | });
408 | if(result.description) {
409 | result.description = result.description.replace(/"/g, '\"\"');
410 | }
411 | // format dates
412 | result.created_at = new Date(result.created_at).toLocaleString();
413 | result.updated_at = new Date(result.updated_at).toLocaleString();
414 | // look up users from unique array
415 | var assignee = _.find(this.users, function(user) { return user.id == result.assignee_id; }),
416 | requester = _.find(this.users, function(user) { return user.id == result.requester_id; }),
417 | submitter = _.find(this.users, function(user) { return user.id == result.submitter_id; });
418 | var collaborators = _.map(result.collaborator_ids, function(id) {
419 | return _.find(this.users, function(user) { return user.id == id; });
420 | }, this);
421 | // replace user ids w/ names
422 | if(assignee) {
423 | result.assignee = assignee.name;
424 | result.assignee_email = assignee.email;
425 | }
426 | else {
427 | result.assignee = result.assignee_id;
428 | result.assignee_email = null;
429 | }
430 | if(requester) {
431 | result.requester = requester.name;
432 | result.requester_email = requester.email;
433 | }
434 | else {
435 | result.requester = result.requester_id;
436 | result.requester_email = null;
437 | }
438 | if(submitter) {
439 | result.submitter = submitter.name;
440 | result.submitter_email = submitter.email;
441 | }
442 | else {
443 | result.submitter = result.submitter_id;
444 | result.submitter_email = null;
445 | }
446 | if(collaborators) {result.collaborators = collaborators;}
447 | //add status labels
448 | result.status_label = helpers.fmt('%@ ', result.status, result.status);
449 | }.bind(this));
450 | // create export
451 | var url;
452 | if (this.exportEnabled === true) {
453 | var data = this.renderTemplate('_tickets_export', {
454 | tickets: results,
455 | columns: this.columns
456 | });
457 | var file = new File([data], 'tickets.csv');
458 | url = URL.createObjectURL(file);
459 | } else {
460 | url = false;
461 | }
462 | // display results
463 | var results_html = this.renderTemplate('results', {
464 | results: results,
465 | // encoded_results: this.encoded,
466 | count: this.numberOfResults,
467 | next_page: this.next_page,
468 | prev_page: this.prev_page,
469 | columns: this.columns,
470 | download: url,
471 | exportEnabled: this.exportEnabled
472 | });
473 | this.$("span.loading").hide();
474 | this.$('div.results').html(results_html);
475 | }
476 | };
477 | }());
478 |
--------------------------------------------------------------------------------