Add in a chepa json dump widget for debugging
[kibble.git] / ui / js / coffee / explorer.coffee
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 explorer = (json, state) ->
17         
18         org = json.organisation
19         h = document.createElement('h2')
20         if json.tag
21             org.name += " (Filter: " + json.tag + ")"
22         h.appendChild(document.createTextNode("Exploring " + org.name + ":"))
23         state.widget.inject(h, true)
24         list = document.createElement('select')
25         state.widget.inject(list)
26         opt = document.createElement('option')
27         opt.value = ""
28         slen = 0
29         for item in json.sources
30             if item.type in ['git', 'svn', 'gerrit', 'github'] and item.noclone != true
31                 slen++
32         opt.text = "All " + slen + " repositories"
33         list.appendChild(opt)
34         json.sources.sort((a,b) ->
35             return if (a.sourceURL == b.sourceURL) then 0 else (if a.sourceURL > b.sourceURL then 1 else -1)
36             )
37         for item in json.sources
38             if item.type in ['git', 'svn', 'gerrit', 'github'] and item.noclone != true
39                 opt = document.createElement('option')
40                 opt.value = item.sourceID
41                 ezURL = null
42                 m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i)
43                 if m and m.length == 3
44                     ezURL = "#{m[2]} - (#{m[1]})"
45                 opt.text = if ezURL then ezURL else item.sourceURL
46                 if globArgs.source and globArgs.source == item.sourceID
47                     opt.selected = 'selected'
48                 list.appendChild(opt)
49         
50         ID = Math.floor(Math.random() * 987654321).toString(16)
51         list.setAttribute('id', ID)
52         $("#"+ID).chosen().change(() ->
53                 source = this.value
54                 
55                 if source == ""
56                         source = null
57                 globArgs.source = source
58                 updateWidgets('donut', null, { source: source })
59                 updateWidgets('gauge', null, { source: source })
60                 updateWidgets('line', null, { source: source })
61                 updateWidgets('contacts', null, { source: source })
62                 updateWidgets('top5', null, { source: source })
63                 updateWidgets('factors', null, { source: source })
64                 updateWidgets('trends', null, { source: source })
65                 updateWidgets('mvp', null, { source: source })
66                 updateWidgets('comstat', null, { source: source })
67                 updateWidgets('jsondump', null, { source: source })
68               )
69         
70         
71         
72         # Unique commits label
73         id = Math.floor(Math.random() * 987654321).toString(16)
74         chk = document.createElement('input')
75         chk.setAttribute("type", "checkbox")
76         chk.setAttribute("id", id)
77         chk.style.marginLeft = '10px'
78         if globArgs.author and globArgs.author == 'true'
79                 chk.checked = true
80         chk.addEventListener("change", () ->
81                 unique = null
82                 if this.checked
83                         author = 'true'
84                         globArgs['author'] = 'true'
85                 
86                 updateWidgets('donut', null, { author: author })
87                 updateWidgets('gauge', null, { author: author })
88                 updateWidgets('line', null, { author: author })
89                 updateWidgets('contacts', null, { author: author })
90                 updateWidgets('top5', null, { author: author })
91                 updateWidgets('factors', null, { author: author })
92                 updateWidgets('trends', null, { author: author })
93                 updateWidgets('relationship', null, {author: author})
94                 updateWidgets('mvp', null, {author: author})
95                 updateWidgets('comstat', null, { author: author })
96                 updateWidgets('jsondump', null, { author: author })
97                 )
98         state.widget.inject(chk)
99         label = document.createElement('label')
100         label.setAttribute("for", id)
101         label.setAttribute("title", "Check this box to authorships instead of committerships")
102         chk.setAttribute("title", "Check this box to authorships instead of committerships")
103         label.style.paddingLeft = '5px'
104         label.appendChild(document.createTextNode('Show authors'))
105         state.widget.inject(label)
106
107
108 sourceexplorer = (json, state) ->
109         
110         org = json.organisation
111         h = document.createElement('h4')
112         if json.tag
113             org.name += " (Filter: " + json.tag + ")"
114         h.appendChild(document.createTextNode("Exploring " + org.name + ":"))
115         state.widget.inject(h, true)
116         div = new HTML('div', {class: "form-group"})
117         list = new HTML('select', { class: "form-control"})
118         div.inject(list)
119         state.widget.inject(div)
120         opt = document.createElement('option')
121         opt.value = ""
122         slen = 0
123         for item in json.sources
124                 slen++
125         opt.text = "All " + slen + " sources"
126         list.appendChild(opt)
127         json.sources.sort((a,b) ->
128             return if (a.sourceURL == b.sourceURL) then 0 else (if a.sourceURL > b.sourceURL then 1 else -1)
129             )
130         for item in json.sources
131             if true
132                 opt = document.createElement('option')
133                 opt.value = item.sourceID
134                 ezURL = null
135                 m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i)
136                 if m and m.length == 3
137                     ezURL = "#{m[2]} - (#{m[1]})"
138                 opt.text = if ezURL then ezURL else item.sourceURL
139                 if globArgs.source and globArgs.source == item.sourceID
140                     opt.selected = 'selected'
141                 list.appendChild(opt)
142                 
143         ID = Math.floor(Math.random() * 987654321).toString(16)
144         list.setAttribute('id', ID)
145         $("#"+ID).chosen().change(() ->
146                 source = this.value
147                 
148                 if source == ""
149                         source = null
150                 globArgs.source = source
151                 updateWidgets('donut', null, { source: source })
152                 updateWidgets('gauge', null, { source: source })
153                 updateWidgets('line', null, { source: source })
154                 updateWidgets('contacts', null, { source: source })
155                 updateWidgets('top5', null, { source: source })
156                 updateWidgets('factors', null, { source: source })
157                 updateWidgets('trends', null, { source: source })
158                 updateWidgets('mvp', null, { source: source })
159                 updateWidgets('comstat', null, { source: source })
160                 updateWidgets('jsondump', null, { author: author })
161         )
162
163
164
165 mailexplorer = (json, state) ->
166         
167         org = json.organisation
168         h = document.createElement('h4')
169         if json.tag
170             org.name += " (Filter: " + json.tag + ")"
171         h.appendChild(document.createTextNode("Exploring " + org.name + ":"))
172         
173         state.widget.inject(h, true)
174         list = document.createElement('select')
175         state.widget.inject(list)
176         opt = document.createElement('option')
177         opt.value = ""
178         slen = 0
179         for item in json.sources
180             if item.type in ['mail', 'ponymail', 'pipermail', 'hyperkitty']
181                 slen++
182         opt.text = "All " + slen + " mailing lists"
183         list.appendChild(opt)
184         json.sources.sort((a,b) ->
185             return if (a.sourceURL == b.sourceURL) then 0 else (if a.sourceURL > b.sourceURL then 1 else -1)
186             )
187         for item in json.sources
188             if item.type in ['mail', 'ponymail', 'pipermail', 'hyperkitty']
189                 opt = document.createElement('option')
190                 opt.value = item.sourceID
191                 ezURL = null
192                 m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i)
193                 if m and m.length == 3
194                     ezURL = "#{m[2]} - (#{m[1]})"
195                 opt.text = if ezURL then ezURL else item.sourceURL
196                 if globArgs.source and globArgs.source == item.sourceID
197                     opt.selected = 'selected'
198                 list.appendChild(opt)
199         
200         ID = Math.floor(Math.random() * 987654321).toString(16)
201         list.setAttribute('id', ID)
202         $("#"+ID).chosen().change(() ->
203                 source = this.value
204                 
205                 if source == ""
206                         source = null
207                 globArgs.source = source
208                 updateWidgets('donut', null, { source: source })
209                 updateWidgets('gauge', null, { source: source })
210                 updateWidgets('line', null, { source: source })
211                 updateWidgets('contacts', null, { source: source })
212                 updateWidgets('top5', null, { source: source })
213                 updateWidgets('factors', null, { source: source })
214                 updateWidgets('trends', null, { source: source })
215                 updateWidgets('relationship', null, { source: source })
216                 
217         )
218         
219 logexplorer = (json, state) ->
220         
221         org = json.organisation
222         h = document.createElement('h4')
223         if json.tag
224             org.name += " (Filter: " + json.tag + ")"
225         h.appendChild(document.createTextNode("Exploring " + org.name + ":"))
226         
227         state.widget.inject(h, true)
228         list = document.createElement('select')
229         state.widget.inject(list)
230         opt = document.createElement('option')
231         opt.value = ""
232         slen = 0
233         for item in json.sources
234             if item.type == 'stats'
235                 slen++
236         opt.text = "All " + slen + " log files"
237         list.appendChild(opt)
238         json.sources.sort((a,b) ->
239             return if (a.sourceURL == b.sourceURL) then 0 else (if a.sourceURL > b.sourceURL then 1 else -1)
240             )
241         for item in json.sources
242             if item.type == 'stats'
243                 opt = document.createElement('option')
244                 opt.value = item.sourceID
245                 ezURL = null
246                 m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i)
247                 if m and m.length == 3
248                     ezURL = "#{m[2]} - (#{m[1]})"
249                 opt.text = if ezURL then ezURL else item.sourceURL
250                 if globArgs.source and globArgs.source == item.sourceID
251                     opt.selected = 'selected'
252                 list.appendChild(opt)
253         
254         ID = Math.floor(Math.random() * 987654321).toString(16)
255         list.setAttribute('id', ID)
256         $("#"+ID).chosen().change(() ->
257                 source = this.value
258                 
259                 if source == ""
260                         source = null
261                 globArgs.source = source
262                 updateWidgets('donut', null, { source: source })
263                 updateWidgets('gauge', null, { source: source })
264                 updateWidgets('line', null, { source: source })
265                 updateWidgets('worldmap', null, { source: source })
266                 updateWidgets('top5', null, { source: source })
267                 updateWidgets('factors', null, { source: source })
268                 updateWidgets('trends', null, { source: source })
269                 
270         )
271         
272 issueexplorer = (json, state) ->
273         
274         org = json.organisation
275         if json.tag
276             org.name += " (Filter: " + json.tag + ")"
277         h = document.createElement('h4')
278         h.appendChild(document.createTextNode("Exploring " + org.name + ":"))
279         state.widget.inject(h, true)
280         list = document.createElement('select')
281         state.widget.inject(list)
282         opt = document.createElement('option')
283         opt.value = ""
284         slen = 0
285         for item in json.sources
286             if item.type in ['jira', 'gerrit', 'github', 'bugzilla']
287                 slen++
288         opt.text = "All " + slen + " issue tracker(s)"
289         list.appendChild(opt)
290         json.sources.sort((a,b) ->
291             return if (a.sourceURL == b.sourceURL) then 0 else (if a.sourceURL > b.sourceURL then 1 else -1)
292             )
293         for item in json.sources
294             if item.type in ['jira', 'gerrit', 'github', 'bugzilla']
295                 opt = document.createElement('option')
296                 opt.value = item.sourceID
297                 ezURL = null
298                 n = item.sourceURL.match(/^([a-z]+:\/\/.+?)\/([-.A-Z0-9]+)$/i)                
299                 m = item.sourceURL.match(/^([a-z]+:\/\/.+?)\s(.+)$/i)
300                 if n and n.length == 3
301                     ezURL = "#{n[2]} - (#{n[1]})"
302                 else if m and m.length == 3
303                     ezURL = "#{m[2]} - (#{m[1]})"
304                 opt.text = if ezURL then ezURL else item.sourceURL
305                 if globArgs.source and globArgs.source == item.sourceID
306                     opt.selected = 'selected'
307                 list.appendChild(opt)
308         
309         ID = Math.floor(Math.random() * 987654321).toString(16)
310         list.setAttribute('id', ID)
311         $("#"+ID).chosen().change(() ->
312                 source = this.value
313                 
314                 if source == ""
315                         source = null
316                 globArgs.source = source
317                 updateWidgets('donut', null, { source: source })
318                 updateWidgets('gauge', null, { source: source })
319                 updateWidgets('line', null, { source: source })
320                 updateWidgets('contacts', null, { source: source })
321                 updateWidgets('top5', null, { source: source })
322                 updateWidgets('factors', null, { source: source })
323                 updateWidgets('trends', null, { source: source })
324                 
325         )
326         
327
328
329
330 imexplorer = (json, state) ->
331         
332         org = json.organisation
333         if json.tag
334             org.name += " (Filter: " + json.tag + ")"
335         h = document.createElement('h4')
336         h.appendChild(document.createTextNode("Exploring " + org.name + ":"))
337         state.widget.inject(h, true)
338         list = document.createElement('select')
339         state.widget.inject(list)
340         opt = document.createElement('option')
341         opt.value = ""
342         slen = 0
343         for item in json.sources
344             if item.type in ['irc','gitter']
345                 slen++
346         opt.text = "All " + slen + " messaging sources"
347         list.appendChild(opt)
348         json.sources.sort((a,b) ->
349             return if (a.sourceURL == b.sourceURL) then 0 else (if a.sourceURL > b.sourceURL then 1 else -1)
350             )
351         for item in json.sources
352             if item.type in ['irc', 'gitter']
353                 opt = document.createElement('option')
354                 opt.value = item.sourceID
355                 ezURL = null
356                 n = item.sourceURL.match(/^([a-z]+:\/\/.+?)\/([#\S+]+)$/i)                
357                 m = item.sourceURL.match(/^([a-z]+:\/\/.+?)\s(.+)$/i)
358                 if n and n.length == 3
359                     ezURL = "#{n[2]} - (#{n[1]})"
360                 else if m and m.length == 3
361                     ezURL = "#{m[2]} - (#{m[1]})"
362                 opt.text = if ezURL then ezURL else item.sourceURL
363                 if globArgs.source and globArgs.source == item.sourceID
364                     opt.selected = 'selected'
365                 list.appendChild(opt)
366         
367         ID = Math.floor(Math.random() * 987654321).toString(16)
368         list.setAttribute('id', ID)
369         $("#"+ID).chosen().change(() ->
370                 source = this.value
371                 
372                 if source == ""
373                         source = null
374                 globArgs.source = source
375                 updateWidgets('donut', null, { source: source })
376                 updateWidgets('gauge', null, { source: source })
377                 updateWidgets('line', null, { source: source })
378                 updateWidgets('contacts', null, { source: source })
379                 updateWidgets('top5', null, { source: source })
380                 updateWidgets('factors', null, { source: source })
381                 updateWidgets('trends', null, { source: source })
382                 
383         , false)
384         $('select').chosen();
385         
386         
387
388 multiviewexplorer = (json, state) ->
389         org = json.organisation
390         h = document.createElement('h4')
391         h.appendChild(document.createTextNode("Select views to compare:"))
392         state.widget.inject(h, true)
393         for k in [1..3]
394             tName = 'tag'+k
395             list = document.createElement('select')
396             list.setAttribute("data", tName)
397             state.widget.inject(list)
398             opt = document.createElement('option')
399             opt.value = ""
400             opt.text = "(None)"
401             list.appendChild(opt)
402             opt = document.createElement('option')
403             opt.value = "---"
404             opt.text = "Entire organisation"
405             if globArgs[tName] and globArgs[tName] == '---'
406                 opt.selected = 'selected'
407             list.appendChild(opt)
408             if isArray(json.views)
409                 json.views.sort((a,b) ->
410                     return if (a.name == b.name) then 0 else (if a.name > b.name then 1 else -1)
411                     )
412             for item in json.views
413                 opt = document.createElement('option')
414                 opt.value = item.id
415                 opt.text = item.name
416                 if globArgs[tName] and globArgs[tName] == item.id
417                     opt.selected = 'selected'
418                 list.appendChild(opt)
419             
420                 ID = Math.floor(Math.random() * 987654321).toString(16)
421                 list.setAttribute('id', ID)
422                 $("#"+ID).chosen().change(() ->
423                     source = this.value
424                     if source == ""
425                             source = null
426                     tName = this.getAttribute("data")
427                     globArgs[tName] = source
428                     x = {}
429                     x[tName] = source
430                     updateWidgets('donut', null, x)
431                     updateWidgets('gauge', null, x)
432                     updateWidgets('line', null, x)
433                     updateWidgets('contacts', null, x)
434                     updateWidgets('top5', null, x)
435                     updateWidgets('factors', null, x)
436                     updateWidgets('trends', null, x)
437                     updateWidgets('radar', null, x)
438               )
439         
440 subFilterGlob = null
441 subFilter = () ->
442         source = subFilterGlob
443         if source == ""
444                 source = null
445         tName = 'subfilter'
446         globArgs[tName] = source
447         x = {}
448         x[tName] = source
449         updateWidgets('sourcepicker', null, x)
450         updateWidgets('repopicker', null, x)
451         updateWidgets('issuepicker', null, x)
452         updateWidgets('mailpicker', null, x)
453         updateWidgets('logpicker', null, x)
454         updateWidgets('donut', null, x)
455         updateWidgets('gauge', null, x)
456         updateWidgets('line', null, x)
457         updateWidgets('contacts', null, x)
458         updateWidgets('top5', null, x)
459         updateWidgets('factors', null, x)
460         updateWidgets('trends', null, x)
461         updateWidgets('radar', null, x)
462         updateWidgets('widget', null, x)
463         updateWidgets('relationship', null, x)
464         updateWidgets('treemap', null, x)
465         updateWidgets('report', null, x)
466         updateWidgets('mvp', null, x)
467         updateWidgets('comstat', null, x)
468         updateWidgets('worldmap', null, x)
469         updateWidgets('jsondump', null, x)
470         
471         $( "a" ).each( () ->
472             url = $(this).attr('href')
473             if url
474                 m = url.match(/^(.+\?page=[-a-z]+.*?)(?:&subfilter=[^&]+)?(.*)$/)
475                 if m
476                     if source
477                             $(this).attr('href', "#{m[1]}&subfilter=#{source}#{m[2]}")
478                     else
479                             $(this).attr('href', "#{m[1]}#{m[2]}")
480         )
481         
482
483 viewexplorer = (json, state) ->
484         org = json.organisation
485         h = document.createElement('h4')
486         h.appendChild(document.createTextNode("Select a view to use:"))
487         state.widget.inject(h, true)
488         tName = 'view'
489         list = document.createElement('select')
490         list.setAttribute("data", tName)
491         state.widget.inject(list)
492         opt = document.createElement('option')
493         opt.value = ""
494         opt.text = "(None)"
495         list.appendChild(opt)
496         opt = document.createElement('option')
497         opt.value = "---"
498         opt.text = "Entire organisation"
499         if globArgs[tName] and globArgs[tName] == '---'
500             opt.selected = 'selected'
501         list.appendChild(opt)
502         if isArray(json.views)
503             json.views.sort((a,b) ->
504                 return if (a.name == b.name) then 0 else (if a.name > b.name then 1 else -1)
505                 )
506         for item in json.views
507             opt = document.createElement('option')
508             opt.value = item.id
509             opt.text = item.name
510             if globArgs[tName] and globArgs[tName] == item.id
511                 opt.selected = 'selected'
512             list.appendChild(opt)
513         
514         ID = Math.floor(Math.random() * 987654321).toString(16)
515         list.setAttribute('id', ID)
516         $("#"+ID).chosen().change(() ->
517                 source = this.value
518                 if source == ""
519                         source = null
520                 tName = this.getAttribute("data")
521                 globArgs[tName] = source
522                 x = {}
523                 x[tName] = source
524                 updateWidgets('sourcepicker', null, x)
525                 updateWidgets('repopicker', null, x)
526                 updateWidgets('issuepicker', null, x)
527                 updateWidgets('mailpicker', null, x)
528                 updateWidgets('logpicker', null, x)
529                 updateWidgets('donut', null, x)
530                 updateWidgets('gauge', null, x)
531                 updateWidgets('line', null, x)
532                 updateWidgets('contacts', null, x)
533                 updateWidgets('top5', null, x)
534                 updateWidgets('factors', null, x)
535                 updateWidgets('trends', null, x)
536                 updateWidgets('radar', null, x)
537                 updateWidgets('widget', null, x)
538                 updateWidgets('relationship', null, x)
539                 updateWidgets('treemap', null, x)
540                 updateWidgets('report', null, x)
541                 updateWidgets('mvp', null, x)
542                 updateWidgets('comstat', null, x)
543                 updateWidgets('worldmap', null, x)
544                 updateWidgets('jsondump', null, x)
545                 
546                 $( "a" ).each( () ->
547                     url = $(this).attr('href')
548                     if url
549                         m = url.match(/^(.+\?page=[-a-z]+)(?:&view=[a-f0-9]+)?(.*)$/)
550                         if m
551                             if source
552                                     $(this).attr('href', "#{m[1]}&view=#{source}#{m[2]}")
553                             else
554                                     $(this).attr('href', "#{m[1]}#{m[2]}")
555                 )
556                 
557         )
558         
559         # Quick filter
560         state.widget.inject(new HTML('br'))
561         i = new HTML('input', {id:'subfilter', type: 'text', value: globArgs.subfilter, onChange: 'subFilterGlob = this.value;', placeholder: 'sub-filter'})
562         b = new HTML('input', {style: { marginLeft: '10px'}, class: 'btn btn-small btn-success', type: 'button', onClick: 'subFilter();', value: "sub-filter"})
563         rb = new HTML('input', {style: { marginLeft: '10px'}, class: 'btn btn-small btn-danger', type: 'button', onClick: 'get("subfilter").value=""; subFilterGlob=""; subFilter();', value: "reset"})
564         state.widget.inject(i)
565         state.widget.inject(b)
566         state.widget.inject(rb)
567         
568         if globArgs.subfilter and globArgs.subfilter.length > 0
569                 source = globArgs.subfilter
570                 $( "a" ).each( () ->
571                         url = $(this).attr('href')
572                         if url
573                             m = url.match(/^(.+\?page=[-a-z]+.*?)(?:&subfilter=[a-f0-9]+)?(.*)$/)
574                             if m
575                                 if source
576                                         $(this).attr('href', "#{m[1]}&subfilter=#{source}#{m[2]}")
577                                 else
578                                         $(this).attr('href', "#{m[1]}#{m[2]}")
579                     )
580         
581         if globArgs.email
582                 div = new HTML('div', {}, "Currently filtering results based on " + globArgs.email + ". - ")
583                 div.inject(new HTML('a', { href: 'javascript:void(filterPerson(null));'}, "Reset filter"))
584                 state.widget.inject(div)
585             
586         
587
588 widgetexplorer = (json, state) ->
589         pwidgets = {
590             'languages': 'Code: Language breakdown',
591             'commit-history-year': "Code: Commit history (past year)"
592             'commit-history-all': "Code: Commit history (all time)"
593             'commit-top5-year': "Code: top 5 committers (past year)"
594             'commit-top5-all': "Code: top 5 committers (all time)"
595             'committer-count-year': "Code: Committers/Authors per month (past year)"
596             'committer-count-all': "Code: Committers/Authors per month (all time)"
597             'commit-lines-year': "Code: Lines changed (past year)"
598             'commit-lines-all': "Code: Lines changed (all time)"
599             'sloc-map': "Code: Language Treemap"
600             'repo-size-year': "Repos: top 15 by lines of code"
601             'repo-commits-year': "Repos: top 15 by number of commits (past year)"
602             'repo-commits-all': "Repos: top 15 by number of commits (all time)"
603             'evolution': "Code: Code evolution (all time)"
604             'evolution-extended': "Code: Code evolution (individual languages, all time)"
605             'issue-count-year': "Issues: Tickets opened/closed (past year)"
606             'issue-count-all': "Issues: Tickets opened/closed (all time)"
607             'issue-operators-year': "Issues: Ticket creators/closers (past year)"
608             'issue-operators-all': "Issues: Ticket creators/closers (all time)"
609             'issue-queue-all': "Issue queue size by ticket age"
610             'email-count-year': "Mail: Emails/threads/authors (past year)"
611             'email-count-all': "Mail: Emails/threads/authors (all time)"
612             'im-stats-year': "Online messaging activity (past year)",
613             'im-stats-all': "Online messaging activity (all time)",
614             'compare-commits-year': "Commits by Affiliation (past year)",
615             'compare-commits-all': "Commits by Affiliation (all time)"
616             'repo-relationship-year': "Repository relationships (past year)"
617             'repo-relationship-2year': "Repository relationships (past two years)"
618             'issue-relationship-year': "Issue tracker relationships (past year)"
619             'issue-relationship-2year': "Issue tracker relationships (past two years)"
620             'log-stats-year': "Downloads/Visits (past year)"
621             'log-stats-all': "Downloads/Visits (all time)"
622             'log-map-month': "Downloads/Visits per country (past month)"
623             'log-map-year': "Downloads/Visits per country (past year)"
624             'log-map-all': "Downloads/Visits per country (all time)"
625         }
626         org = json.organisation
627         h = document.createElement('h4')
628         h.appendChild(document.createTextNode("Select a widget to use:"))
629         state.widget.inject(h, true)
630         tName = 'widget'
631         list = document.createElement('select')
632         list.setAttribute("data", tName)
633         state.widget.inject(list)
634         opt = document.createElement('option')
635         opt.value = ""
636         opt.text = "Select a widget type:"
637         list.appendChild(opt)
638         for key, value of pwidgets
639             opt = document.createElement('option')
640             opt.value = key
641             opt.text = value
642             if globArgs[tName] and globArgs[tName] == key
643                 opt.selected = 'selected'
644             list.appendChild(opt)
645         
646         list.addEventListener("change", () ->
647                 source = this.value
648                 if source == ""
649                         source = null
650                 tName = this.getAttribute("data")
651                 globArgs[tName] = source
652                 x = {}
653                 x[tName] = source
654                 updateWidgets('widget', null, x)
655                 updateWidgets('donut', null, x)
656                 updateWidgets('gauge', null, x)
657                 updateWidgets('line', null, x)
658                 updateWidgets('contacts', null, x)
659                 updateWidgets('top5', null, x)
660                 updateWidgets('factors', null, x)
661                 updateWidgets('trends', null, x)
662                 updateWidgets('radar', null, x)
663                 
664         , false)
665             
666