import
[web.mtrack] / web / query.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3
4 include '../inc/common.php';
5
6 mtrack_head("Custom Query");
7
8 echo "<h1>Custom Query</h1>\n";
9
10 /* This logic matches up to equivalent logic in the macro_RunReport
11  * function in inc/report */
12
13 $params = array();
14
15 if (strlen($_SERVER['QUERY_STRING'])) {
16   $qs = $_SERVER['QUERY_STRING'];
17 } else {
18   $qs = mtrack_get_pathinfo();
19 }
20
21 list ($params, $mparams) = MTrackReport::parseQuery($qs);
22
23 echo "<form action='{$ABSWEB}query.php' method='get' id='qform' onsubmit='return false;'>";
24 echo "<table id='qtable'></table></form>";
25
26 $params = json_encode($params);
27
28 $milestones = json_encode(array_values(MTrackMilestone::enumMilestones(true)));
29 echo <<<HTML
30 <form id='customqryaddfilter'>
31 Add Filter: <select id='addfilt'>
32 <option value="">- Select to add a filter</option>
33 HTML;
34
35 $fields = array('cc', 'component', 'milestone', 'status', 'owner',
36   'type', 'summary', 'ticket', 'priority', 'keyword');
37
38 asort($fields);
39 $labels = array();
40
41 foreach ($fields as $field) {
42   echo "<option value='$field'>" . ucfirst($field) . "</option>\n";
43   $labels[$field] = ucfirst($field);
44 }
45 $C = MTrackTicket_CustomFields::getInstance();
46 $custom_fields = new stdclass;
47 foreach ($C->fields as $f) {
48   echo "<option value='$f->name'>" .
49     htmlentities($f->label, ENT_QUOTES, 'utf-8') . "</option>\n";
50   $labels[$f->name] = $f->label;
51   if ($f->type == 'select' || $f->type == 'multiselect') {
52     $d = $f->ticketData();
53     $custom_fields->{$f->name} = array_values($d['options']);
54   }
55 }
56 echo <<<HTML
57 </select>
58 <br>
59 <div id='colselector'>
60 <h3><a href='#'>Choose Columns (drag to re-order)</a></h3>
61 <div style="display:none">
62 <ul id='columns'>
63 HTML;
64
65 $labels = json_encode($labels);
66 $custom_fields = json_encode($custom_fields);
67 $c = new MTrackClassification;
68 $classifications = json_encode(array_values($c->enumerate()));
69 $c = new MTrackPriority;
70 $priorities = json_encode(array_values($c->enumerate()));
71 /* Allow selection of columns */
72 function add_col($name, $label) {
73   global $mparams;
74   $checked = in_array($name, $mparams['col']) ? ' checked="yes" ' : '';
75   $label = htmlentities($label, ENT_QUOTES, 'utf-8');
76   echo "<li class='ui-state-default'><input type='checkbox' name='col_$name' mtrackcol='$name' class='qrycol' $checked> ";
77   echo "<label for='col_$name'>$label</label></li> ";
78 }
79 $all_cols = array();
80
81 // Add in the selected columns in order first
82 foreach ($mparams['col'] as $col) {
83   $field = $C->fieldByName($col);
84   if ($field) {
85     $all_cols[$field->name] = $field->label;
86   } else {
87     $all_cols[$col] = ucfirst($col);
88   }
89 }
90 // Add in other possible fields
91 foreach ($fields as $field) {
92   $all_cols[$field] = ucfirst($field);
93 }
94 $possible_fields = array(
95   'severity', 'remaining'
96 );
97 foreach ($possible_fields as $name) {
98   $all_cols[$name] = ucfirst($name);
99 }
100 foreach ($C->fields as $f) {
101   $all_cols[$f->name] = $f->label;
102 }
103
104 foreach ($all_cols as $name => $label) {
105   add_col($name, $label);
106 }
107
108 echo <<<HTML
109 </ul>
110 </div>
111 </div>
112 </form>
113 <button id='updfilt'>Update</button><br>
114 <script language='javascript' type='text/javascript'>
115 var initq = $params;
116 var milestones = $milestones;
117 var classifications = $classifications;
118 var priorities = $priorities;
119 var next_field_id = 1;
120 var adding_field = false;
121 var custom_fields = $custom_fields;
122 var field_labels = $labels;
123
124 function mtrack_add_sel(sel, a, b)
125 {
126   sel.options[sel.options.length] = new Option(a, b);
127 }
128
129 // given a field name, operator and value, create a new entry in the form
130 function mtrack_add_field(name, op, value)
131 {
132   var qtable = document.getElementById('qtable');
133
134   // <tr><td>X</td><td>name</td><td>op select</td><td>value</td></tr>
135   var tr = document.createElement('tr');
136   var xcell = document.createElement('td');
137   var but = document.createElement('button');
138   but.innerHTML = "X";
139   xcell.appendChild(but);
140   xcell.onclick = function() {
141     qtable.removeChild(tr);
142     return false;
143   };
144   tr.appendChild(xcell);
145
146   var ncell = document.createElement('td');
147   ncell.innerHTML = field_labels[name];
148   ncell.align = "right";
149   var ntype = document.createElement('input');
150   ntype.type = 'hidden';
151   ntype.id = "optyp_" + next_field_id;
152   ntype.name = ntype.id;
153   ntype.value = name;
154   ncell.appendChild(ntype);
155   tr.appendChild(ncell);
156
157   var opcell = document.createElement('td');
158   // create the operator map
159   var sel = document.createElement('select');
160   sel.id = "opsel_" + next_field_id;
161   sel.name = sel.id;
162   mtrack_add_sel(sel, "is", "=");
163   mtrack_add_sel(sel, "is not", "!=");
164
165   if (name != 'milestone' && name != 'status' && name != 'type') {
166     mtrack_add_sel(sel, "contains", "~=");
167     mtrack_add_sel(sel, "does not contain", "!~=");
168     mtrack_add_sel(sel, "starts with", "^=");
169     mtrack_add_sel(sel, "does not start with", "!^=");
170     mtrack_add_sel(sel, "ends with", "\$=");
171     mtrack_add_sel(sel, "does not end with", "!\$=");
172   }
173   var i;
174   for (i = 0; i < sel.length; i++) {
175     if (sel.options[i].value == op) {
176       sel.selectedIndex = i;
177       break;
178     }
179   }
180
181   opcell.appendChild(sel);
182   tr.appendChild(opcell);
183
184   var vid = "opval_" + next_field_id;
185
186   var vcell = document.createElement('td');
187   var vele = null;
188
189   if (name == 'milestone') {
190     vele = document.createElement('select');
191     for (i in milestones) {
192       mtrack_add_sel(vele, milestones[i], milestones[i]);
193       if (milestones[i] == value) {
194         vele.selectedIndex = vele.length - 1;
195       }
196     }
197   } else if (name == 'status') {
198     vele = document.createElement('select');
199     mtrack_add_sel(vele, 'new', 'new');
200     mtrack_add_sel(vele, 'open', 'open');
201     mtrack_add_sel(vele, 'closed', 'closed');
202     mtrack_add_sel(vele, 'assigned', 'assigned');
203     switch (value) {
204       case 'new': vele.selectedIndex = 0; break;
205       case 'open': vele.selectedIndex = 1; break;
206       case 'closed': vele.selectedIndex = 2; break;
207       case 'assigned': vele.selectedIndex = 3; break;
208     }
209   } else if (name == 'type') {
210     vele = document.createElement('select');
211     for (i in classifications) {
212       mtrack_add_sel(vele, classifications[i], classifications[i]);
213       if (classifications[i] == value) {
214         vele.selectedIndex = vele.length - 1;
215       }
216     }
217   } else if (name == 'priority') {
218     vele = document.createElement('select');
219     for (i in priorities) {
220       mtrack_add_sel(vele, priorities[i], priorities[i]);
221       if (priorities[i] == value) {
222         vele.selectedIndex = vele.length - 1;
223       }
224     }
225   } else if (custom_fields[name]) {
226     vele = document.createElement('select');
227     var opts = custom_fields[name];
228     for (i in opts) {
229       mtrack_add_sel(vele, opts[i], opts[i]);
230       if (opts[i] == value) {
231         vele.selectedIndex = vele.length - 1;
232       }
233     }
234   }
235
236   if (vele == null) {
237     // default to a text entry field
238     vele = document.createElement('input');
239     vele.type = 'text';
240     vele.value = value;
241   }
242   vele.name = vid;
243   vele.id = vid;
244   vcell.appendChild(vele);
245   tr.appendChild(vcell);
246
247   qtable.appendChild(tr);
248   \$(vele).bind('keypress', function (e) {
249     switch (e.keyCode) {
250       case $.ui.keyCode.ENTER:
251       case $.ui.keyCode.BACKSPACE:
252         return false;
253     }
254   });
255
256   next_field_id++;
257 }
258
259 $(document).ready(function (){
260   $('#colselector').accordion({
261     collapsible: true,
262     active: false
263   });
264   $('#columns').sortable();
265
266   // decode the parameters and build out the form
267   var prop;
268   for (prop in initq) {
269     var d = initq[prop];
270     var op = d[0];
271     var values = d[1];
272     var val;
273     for (val in values) {
274       mtrack_add_field(prop, op, values[val]);
275     }
276   }
277
278   $('#addfilt').change(function () {
279     if (!adding_field) {
280       adding_field = true;
281       mtrack_add_field(this.options[this.selectedIndex].value, null, null);
282       this.selectedIndex = 0;
283       adding_field = false;
284     }
285   });
286
287   $('#updfilt').click(function (){
288     var filt = [];
289     // Iterate the form elements and build up the query string
290     var i;
291     var f = document.getElementById('qform');
292     for (i = 0; i < f.length; i++) {
293       var ele = f.elements[i];
294       if (ele.name.match(/^op(sel|val|typ)_/)) {
295         var fid = ele.name.substr(6);
296         var oper = document.getElementById('opsel_' + fid);
297         var val = document.getElementById('opval_' + fid);
298         var type = document.getElementById('optyp_' + fid);
299         filt[fid] = [type.value, oper.value, val.value];
300       }
301     }
302     var qs = "";
303     for (i in filt) {
304       f = filt[i];
305       if (qs.length) {
306         qs += "&";
307       }
308       qs += f[0] + f[1] + f[2];
309     }
310     // And the columns
311     var col = [];
312     $('input.qrycol:checked').each(function () {
313       col[col.length] = $(this).attr('mtrackcol');
314     });
315     qs = qs + "&col=" + col.join('|');
316     document.location.href = "{$ABSWEB}query.php?" + qs;
317     return false;
318   });
319 });
320 </script>
321 HTML;
322
323 if (strlen(trim($qs))) {
324   echo MTrackReport::macro_TicketQuery($qs);
325 }
326
327 mtrack_foot();
328