I18N: Make everything in tt2 files translatable.
[working/Evergreen.git] / Open-ILS / src / templates / actor / user / event_log.tt2
1 [% WRAPPER base.tt2 %]
2 [% ctx.page_title = l("Triggered Event Log") %]
3 <script type="text/javascript">
4     dojo.require("dijit.form.Button");
5     dojo.require("dojo.data.ItemFileReadStore");
6     dojo.require("openils.CGI");
7     dojo.require("openils.widget.FlattenerGrid");
8     dojo.require("openils.widget.OrgUnitFilteringSelect");
9     dojo.require("openils.widget.ProgressDialog");
10
11     /* If you want to expand this list of supported core_types, you must also
12        change openils.widget._FSBuilder.CoreType further down, so that it
13        includes labels for these in its data store for filter widget
14        purposes. */
15     var initial_query = {"core_type": ["circ", "ahr"]};
16
17     /* Pre-filter by patron ID or copy ID if those are passed in as CGI
18        parameters.  It's an either-or proposition for now. */
19     var cgi = new openils.CGI();
20     var patron_id = cgi.param("patron_id");
21     var copy_id = cgi.param("copy_id");
22
23     /* These features depends on target_{circ,hold}_{patron,copy}_id fields
24        being present in map_extras later. */
25     if (patron_id) {
26         initial_query["-or"] = {
27             "target_circ_patron_id": patron_id,
28             "target_hold_patron_id": patron_id
29         };
30         openils.Util.addOnLoad(
31             function() { openils.Util.show("patron_specific", "inline"); }
32         );
33     } else if (copy_id) {
34         initial_query["-or"] = {
35             "target_circ_copy_id": copy_id,
36             "target_hold_copy_id": copy_id
37         };
38         openils.Util.addOnLoad(
39             function() { openils.Util.show("copy_specific", "inline"); }
40         );
41     }
42
43     /* This semaphore business exists to prevent a race condition. Both
44        the OrgUnitFilteringSelect and the FlattenerFilterPane try to refresh
45        the grid when they're done loading, but that doesn't need to happen
46        until they're /both/ done loading. */
47     var _filter_semaphore_ctr = 2;
48     function filter_semaphore() { return --_filter_semaphore_ctr <= 0; }
49     function filter_semaphore_callback() {
50         grid.fetchLock = false;
51         grid.filterUi.doApply();
52     }
53
54     var _reactors_cache;
55
56     /* This and its subclasses exist because *FilterPane expect things that
57        act like AutoFieldWidget, which is a widget /builder/.  */
58     dojo.declare(
59         "openils.widget._FSBuilder", null, {
60             "dijitArgs": null,
61             "parentNode": null,
62             "useCorrectly": true,
63
64             "constructor": function(args) {
65                 dojo.mixin(this, args);
66             },
67
68             "build": function() {
69                 var dijitArgs = dojo.mixin(
70                     {
71                         "store": this.store || this.storeBuilder(),
72                         "query": {},
73                         "labelAttr": "label",
74                         "searchAttr": "label",
75                     }, this.dijitArgs
76                 );
77
78                 this.widget =
79                     new dijit.form.FilteringSelect(dijitArgs, this.parentNode);
80             }
81         }
82     );
83
84     dojo.declare(
85         "openils.widget._FSBuilder.Reactor",
86         [openils.widget._FSBuilder], {
87             "storeBuilder": function() {
88                 _reactors_cache = _reactors_cache ||
89                     fieldmapper.standardRequest(
90                         ["open-ils.actor", "open-ils.actor.action_trigger.reactors.all_in_use"],
91                         { "params": [openils.User.authtoken] }
92                     ).sort();
93                 return new dojo.data.ItemFileReadStore({
94                     "data": {
95                         "identifier": "name",
96                         "items": _reactors_cache.map(
97                             function(o) { return {"name": o, "label": o}; }
98                         )
99                     }
100                 });
101             }
102         }
103     );
104
105     dojo.declare(
106         "openils.widget._FSBuilder.CoreType",
107         [openils.widget._FSBuilder], {
108             "store": new dojo.data.ItemFileReadStore({
109                 "data": {
110                     "identifier": "name",
111                     "items": [  /* XXX i18n */
112                         {"name": "circ", "label": "[% l('Circulation') %]"},
113                         {"name": "ahr", "label": "[% l('Hold') %]"}
114                     ]
115                 }
116             })
117         }
118     );
119
120     dojo.declare(
121         "openils.widget._FSBuilder.EventState",
122         [openils.widget._FSBuilder], {
123             "store": new dojo.data.ItemFileReadStore({
124                 "data": {
125                     "identifier": "name",
126                     "items": [  /* XXX i18n */
127                         {"name": "found", "label": "[% l('Found') %]"},
128                         {"name": "collected", "label": "[% l('Collected') %]"},
129                         {"name": "invalid", "label": "[% l('Invalid') %]"},
130                         {"name": "pending", "label": "[% l('Pending') %]"},
131                         {"name": "reacting", "label": "[% l('Reacting') %]"},
132                         {"name": "complete", "label": "[% l('Complete') %]"},
133                         {"name": "error", "label": "[% l('Error') %]"}
134                     ]
135                 }
136             })
137         }
138     );
139
140     /* Various things with which to initialize FlattenerGrid. */
141     var map_extras = {
142         "core_type": {"path": "hook.core_type", "filter": true},
143         "perm_lib": {"path": "perm_lib", "filter": true},
144         "target_circ_patron_id": {"path": "target_circ.usr", "filter": true},
145         "target_hold_patron_id": {"path": "target_hold.usr", "filter": true},
146         "target_circ_copy_id":{"path":"target_circ.target_copy","filter":true},
147         "target_hold_copy_id":{"path":"target_hold.current_copy","filter":true}
148     };
149
150     var filter_initializers = [
151         {"field": "state", "operator": "=", "value": "complete"},
152         {"field": "core_type", "operator": "=", "value": "circ"}
153     ];
154
155     var filter_widget_builders = {
156         "ath:core_type": openils.widget._FSBuilder.CoreType,
157         "atul:state": openils.widget._FSBuilder.EventState,
158         "atul:reactor": openils.widget._FSBuilder.Reactor,
159     };
160
161     function print_all() {
162         var n;
163         if ((n = parseInt(prompt('[% l("Up to how many rows?") %]','100'))) > 0)
164             grid.print(n);
165     }
166
167     function act_on_events(id_list, action) {
168         console.log(id_list);
169         var method = "open-ils.actor.user.event." + action + ".batch";
170         if (id_list.length < 1) {
171             alert("[% l('You selected nothing.') %]");
172             return;
173         }
174
175         var count = 0;
176         progress_dialog.show(true);
177         fieldmapper.standardRequest(
178             ["open-ils.actor", method], {
179                 "async": true,
180                 "params": [openils.User.authtoken, id_list],
181                 "onresponse": function(r) {
182                     if (r = openils.Util.readResponse(r)) {
183                         progress_dialog.update(
184                             {"maximum": id_list.length, "progress": ++count}
185                         );
186                     }
187                 },
188                 "oncomplete": function(r) {
189                     progress_dialog.hide();
190                     r = openils.Util.readResponse(r);
191                     grid.refresh();
192                 }
193             }
194         );
195     }
196
197     /* The callback fired when the OrgUnitFilteringSelect is changed */
198     function set_grid_query_from_org_selector() {
199         /* Naughty: shouldn't use _baseQuery like this, but need to rethink
200            multiple competing filtering mechanisms. */
201         grid._baseQuery.perm_lib = aou.descendantNodeList(
202             org_selector.attr("value"), /* as id */ true
203         );
204
205         /* But for the persistent filter UI, this would be grid.refresh() */
206         if (filter_semaphore())   /* avoid race between ou selector and other
207                                      filter thing */
208             filter_semaphore_callback();
209     }
210
211     /* Builds a OrgUnitFilteringSelect limited to org units where you have
212        a given permission. */
213     function prepare_org_selector(perm) {
214         new openils.User().buildPermOrgSelector(
215             perm, org_selector, null,
216             function() {
217                 dojo.connect(
218                     org_selector, "onChange", set_grid_query_from_org_selector
219                 );
220                 set_grid_query_from_org_selector();
221             }
222         );
223     }
224
225     openils.Util.addOnLoad(
226         function() {
227             prepare_org_selector("VIEW_TRIGGER_EVENT");
228         }
229     );
230 </script>
231 <div dojoType="dijit.layout.ContentPane" layoutAlign="client">
232     <div dojoType="dijit.layout.ContentPane"
233          layoutAlign="top" class="oils-header-panel">
234         <div>
235             [% ctx.page_title %]
236             <span id="copy_specific" class="hidden">([% l('copy specific') %])</span>
237             <span id="patron_specific" class="hidden">([% l('patron specific') %])</span>
238         </div>
239         <div>
240             <button dojoType="dijit.form.Button"
241                 onClick="act_on_events(grid.getSelectedIDs(), 'reset');">[% l('Reset Selected Events') %]</button>
242             <button dojoType="dijit.form.Button"
243                 onClick="act_on_events(grid.getSelectedIDs(), 'cancel');">[% l('Cancel Selected Events') %]</button>
244             <button dojoType="dijit.form.Button"
245                 onClick="grid.printSelected();">[% l('Print Selected Events') %]</button>
246             <button dojoType="dijit.form.Button"
247                 onClick="print_all();">[% l('Print All Events') %]</button>
248         </div>
249     </div>
250     <div class="oils-acq-basic-roomy">
251         <label for="org_selector">[% l('Show events at and below') %]:</label>
252         <select
253             id="org_selector" jsId="org_selector"
254             dojoType="openils.widget.OrgUnitFilteringSelect"
255             searchAttr="name" labelAttr="name">
256         </select>
257     </div>
258     <div>
259         <div style="float: left; width: 66%;">
260             <table id="gridNode"
261                 jsid="grid"
262                 dojoType="openils.widget.FlattenerGrid"
263                 columnPersistKey='"ui.grid_columns.actor.user.event_log"'
264                 autoHeight="10"
265                 selectable="true"
266                 editOnEnter="false"
267                 showLoadFilter="true"
268                 filterAlwaysInDiv="'filter_holder'"
269                 filterInitializers="filter_initializers"
270                 filterWidgetBuilders="filter_widget_builders"
271                 filterSemaphore="filter_semaphore"
272                 filterSemaphoreCallback="filter_semaphore_callback"
273                 fmClass="'atul'"
274                 autoFieldFields="['target_hold','target_circ']"
275                 defaultSort="['run_time']"
276                 mapExtras="map_extras"
277                 fetchLock="true"
278                 query="initial_query">
279                 <thead>
280                     <tr>
281                         <th field="name" fpath="name" ffilter="true">[% l('Event Name') %]</th>
282                         <th field="reactor" fpath="reactor" ffilter="true"></th>
283                         <th field="run_time" fpath="run_time" ffilter="true"></th><!-- XXX TODO formatters for *_time -->
284                         <th field="add_time" fpath="add_time" ffilter="true" _visible="false"></th>
285                         <th field="start_time" fpath="start_time" ffilter="true" _visible="false"></th>
286                         <th field="update_time" fpath="update_time" ffilter="true" _visible="false"></th>
287                         <th field="complete_time" fpath="complete_time" ffilter="true" _visible="false"></th>
288                         <th field="id" fpath="id" ffilter="true" _visible="false"></th>
289                         <th field="state" fpath="state" ffilter="true"></th>
290                         <th field="target_circ_copy_barcode" fpath="target_circ.target_copy.barcode" ffilter="true">[% l('Target Circulation - Copy Barcode') %]</th>
291                         <th field="target_circ_copy_title" fpath="target_circ.target_copy.call_number.record.simple_record.title">[% l('Target Circulation - Title') %]</th>
292                         <th field="target_circ_copy_author" fpath="target_circ.target_copy.call_number.record.simple_record.author">[% l('Target Circulation - Author') %]</th>
293                         <th field="target_circ_patron_barcode" fpath="target_circ.usr.card.barcode" ffilter="true">[% l('Target Circulation - Patron Barcode') %]</th>
294                         <th field="target_hold_copy_title" fpath="target_hold.current_copy.call_number.record.simple_record.title">[% l('Target Hold - Title') %]</th>
295                         <th field="target_hold_copy_author" fpath="target_hold.current_copy.call_number.record.simple_record.author">[% l('Target Hold - Author') %]</th>
296                         <th field="target_hold_patron_barcode" fpath="target_hold.usr.card.barcode" ffilter="true">[% l('Target Hold - Patron Barcode') %]</th>
297                     </tr>
298                 </thead>
299             </table>
300         </div>
301         <div style="float: right; width: 33%;">
302             <div id="filter_holder"></div>
303         </div>
304         <div style="clear: both;"></div>
305     </div>
306 </div>
307 <div dojoType="openils.widget.ProgressDialog" jsId="progress_dialog"></div>
308 [% END %]