You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kibble.apache.org by hu...@apache.org on 2018/01/17 18:37:36 UTC

[kibble] branch master updated (5a4d7fa -> 48f3e58)

This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/kibble.git.


    from 5a4d7fa  teaser and URL in README
     new 6fa9dbb  nix svn for now - unsure how we would incorporate it
     new cdfbe83  Add in a chepa json dump widget for debugging
     new c377dbe  rough in a comstat-like page
     new e335c4b  regen openapi specs
     new 39a75dc  fix up comstat widget, add it to the widget yaml list
     new 48f3e58  regen JS

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 api/pages/bio/newtimers.py          | 356 ++++++++++++++++++++++++++++++++++++
 api/yaml/openapi.yaml               |  40 ++++
 api/yaml/sourcetypes.yaml           |   4 -
 api/yaml/widgets.yaml               |  31 ++++
 docs/source/managing.rst            |   3 -
 ui/js/coffee/datepicker.coffee      |   1 +
 ui/js/coffee/explorer.coffee        |   5 +
 ui/js/coffee/pageloader.coffee      |   1 +
 ui/js/coffee/widget.coffee          |   1 +
 ui/js/coffee/widget_comstat.coffee  | 167 +++++++++--------
 ui/js/coffee/widget_jsondump.coffee |   5 +
 ui/js/kibble.v1.js                  | 300 +++++++++++++++++-------------
 12 files changed, 700 insertions(+), 214 deletions(-)
 create mode 100644 api/pages/bio/newtimers.py
 create mode 100644 ui/js/coffee/widget_jsondump.coffee

-- 
To stop receiving notification emails like this one, please contact
['"commits@kibble.apache.org" <co...@kibble.apache.org>'].

[kibble] 03/06: rough in a comstat-like page

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kibble.git

commit c377dbee59308927ad0d9ff113c1d8f29a718005
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Wed Jan 17 19:36:33 2018 +0100

    rough in a comstat-like page
    
    This needs to be reworked a bit later on, but it works...
    albeit super slow!
---
 api/pages/bio/newtimers.py | 356 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 356 insertions(+)

diff --git a/api/pages/bio/newtimers.py b/api/pages/bio/newtimers.py
new file mode 100644
index 0000000..41537f7
--- /dev/null
+++ b/api/pages/bio/newtimers.py
@@ -0,0 +1,356 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+########################################################################
+# OPENAPI-URI: /api/bio/newtimers
+########################################################################
+# get:
+#   responses:
+#     '200':
+#       content:
+#         application/json:
+#           schema:
+#             $ref: '#/components/schemas/Biography'
+#       description: 200 Response
+#     default:
+#       content:
+#         application/json:
+#           schema:
+#             $ref: '#/components/schemas/Error'
+#       description: unexpected error
+#   security:
+#   - cookieAuth: []
+#   summary: Shows some facts about a contributor
+# post:
+#   requestBody:
+#     content:
+#       application/json:
+#         schema:
+#           $ref: '#/components/schemas/defaultWidgetArgs'
+#   responses:
+#     '200':
+#       content:
+#         application/json:
+#           schema:
+#             $ref: '#/components/schemas/Biography'
+#       description: 200 Response
+#     default:
+#       content:
+#         application/json:
+#           schema:
+#             $ref: '#/components/schemas/Error'
+#       description: unexpected error
+#   security:
+#   - cookieAuth: []
+#   summary: Shows some facts about a contributor
+# 
+########################################################################
+
+
+
+
+
+"""
+This is the newtimers list renderer for Kibble
+"""
+
+import json
+import time
+import hashlib
+
+def find_earlier(session, query, when, who, which, where, doctype, dOrg):
+    """Find earlier document pertaining to this user. return True if found"""
+    if 'aggs' in query:
+        del query['aggs']
+        
+    rangeQuery = {'range':
+                    {
+                        which: {
+                            'from': 0,
+                            'to': time.time()
+                        }
+                    }
+                }
+    
+    query['query']['bool']['must'] = [
+        rangeQuery,
+        {
+            'term': {
+                'organisation': dOrg
+            }
+        },
+        {
+            'term': {
+                where: who
+            }
+            
+        }
+        ]
+    query['size'] = 1
+    query['sort'] = [{ which: 'asc' }]
+    
+    res = session.DB.ES.search(
+        index=session.DB.dbname,
+        doc_type=doctype,
+        body = query
+    )
+    if res['hits']['hits']:
+        doc = res['hits']['hits'][0]['_source']
+        if doc[which] >= when:
+            return [doc[which], doc]
+        else:
+            return [-1, None]
+    else:
+        return [-1, None]
+    
+
+def run(API, environ, indata, session):
+    
+    # We need to be logged in for this!
+    if not session.user:
+        raise API.exception(403, "You must be logged in to use this API endpoint! %s")
+    
+    now = time.time()
+    
+    # First, fetch the view if we have such a thing enabled
+    viewList = []
+    if indata.get('view'):
+        viewList = session.getView(indata.get('view'))
+    if indata.get('subfilter'):
+        viewList = session.subFilter(indata.get('subfilter'), view = viewList) 
+    
+    
+    dOrg = session.user['defaultOrganisation'] or "apache"
+    
+    
+    # Keep track of all contributors, and newcomers
+    contributors = []
+    newcomers = {}
+    
+    ####################################################################
+    # Start by grabbing all contributors this period via terms agg     #
+    ####################################################################
+    dateTo = indata.get('to', int(time.time()))
+    dateFrom = indata.get('from', dateTo - (86400*30*6)) # Default to a 6 month span
+    
+    
+    
+    
+    ############################
+    # CODE NEWTIMERS           #
+    ############################
+    rangeKey = 'ts'
+    rangeQuery = {'range':
+                    {
+                        rangeKey: {
+                            'from': dateFrom,
+                            'to': dateTo
+                        }
+                    }
+                }
+    
+    query = {
+                'query': {
+                    'bool': {
+                        'must': [
+                            rangeQuery,
+                            {
+                                'term': {
+                                    'organisation': dOrg
+                                }
+                            }
+                        ]
+                    }
+                }
+            }
+    
+    query['aggs'] = {
+        'by_committer': {
+            'terms': {
+                'field': 'committer_email',
+                'size': 500
+            }                
+        },
+        'by_author': {
+            'terms': {
+                'field': 'author_email',
+                'size': 500
+            }                
+        }
+    }
+    
+    # Source-specific or view-specific??
+    if indata.get('source'):
+        query['query']['bool']['must'].append({'term': {'sourceID': indata.get('source')}})
+    elif viewList:
+        query['query']['bool']['must'].append({'terms': {'sourceID': viewList}})
+    
+    
+    res = session.DB.ES.search(
+            index=session.DB.dbname,
+            doc_type="code_commit",
+            body = query
+        )
+    
+    code_contributors = []
+    for bucket in res['aggregations']['by_committer']['buckets']:
+        email = bucket['key']
+        if email not in code_contributors:
+            code_contributors.append(email)
+    
+    for bucket in res['aggregations']['by_author']['buckets']:
+        email = bucket['key']
+        if email not in code_contributors:
+            code_contributors.append(email)
+    
+    # Now, for each contributor, find if they have done anything before
+    for email in code_contributors:
+        ea = find_earlier(session, query, dateFrom, email, 'ts', 'author_email', 'code_commit', dOrg)
+        ec = find_earlier(session, query, dateFrom, email, 'ts', 'committer_email', 'code_commit', dOrg)
+        if ea[0] != -1 and ec[0] != -1:
+            earliest = ea
+            if earliest[0] == -1 or (earliest[0] > ec[0] and ec[0] != -1):
+                earliest = ec
+            newcomers[email] = {
+                'code': earliest
+            }
+    
+    
+    
+    ############################
+    # ISSUE NEWTIMERS          #
+    ############################
+    rangeKey = 'created'
+    rangeQuery = {'range':
+                    {
+                        rangeKey: {
+                            'from': dateFrom,
+                            'to': dateTo
+                        }
+                    }
+                }
+    
+    query = {
+                'query': {
+                    'bool': {
+                        'must': [
+                            rangeQuery,
+                            {
+                                'term': {
+                                    'organisation': dOrg
+                                }
+                            }
+                        ]
+                    }
+                }
+            }
+    
+    query['aggs'] = {
+        'by_creator': {
+            'terms': {
+                'field': 'issueCreator',
+                'size': 500
+            }                
+        },
+        'by_closer': {
+            'terms': {
+                'field': 'issueCloser',
+                'size': 500
+            }                
+        }
+    }
+    
+    # Source-specific or view-specific??
+    if indata.get('source'):
+        query['query']['bool']['must'].append({'term': {'sourceID': indata.get('source')}})
+    elif viewList:
+        query['query']['bool']['must'].append({'terms': {'sourceID': viewList}})
+    
+    
+    res = session.DB.ES.search(
+            index=session.DB.dbname,
+            doc_type="issue",
+            body = query
+        )
+    
+    issue_contributors = []
+    for bucket in res['aggregations']['by_creator']['buckets']:
+        email = bucket['key']
+        if email not in issue_contributors:
+            issue_contributors.append(email)
+    
+    for bucket in res['aggregations']['by_closer']['buckets']:
+        email = bucket['key']
+        if email not in issue_contributors:
+            issue_contributors.append(email)
+    
+    # Now, for each contributor, find if they have done anything before
+    for email in issue_contributors:
+        ecr = find_earlier(session, query, dateFrom, email, 'created', 'issueCreator', 'issue', dOrg)
+        ecl = find_earlier(session, query, dateFrom, email, 'closed', 'issueCloser', 'issue', dOrg)
+        if ecr[0] != -1 and ecl[0] != -1:
+            earliest = ecr
+            if earliest[0] == -1 or (earliest[0] > ecl[0] and ecl[0] != -1):
+                earliest = ecl
+            newcomers[email] = newcomers.get(email, {})
+            newcomers[email]['issue'] = earliest
+    
+    email_contributors = []
+    
+    ################################
+    # For each newtimer, get a bio #
+    ################################
+    
+    for email in newcomers:
+        pid = hashlib.sha1( ("%s%s" % (dOrg, email)).encode('ascii', errors='replace')).hexdigest()
+        person = {}
+        if session.DB.ES.exists(index=session.DB.dbname, doc_type="person", id = pid):
+            person = session.DB.ES.get(index=session.DB.dbname, doc_type="person", id = pid)['_source']
+        newcomers[email]['bio'] = person
+    
+    newcomers_code = []
+    newcomers_issues = []
+    newcomers_email = []
+    
+    # Count newcomers in each category (TODO: put this elsewhere earlier)
+    for email, entry in newcomers.items():
+        if 'code' in entry:
+            newcomers_code.append(email)
+        if 'issue' in entry:
+            newcomers_issues.append(email)
+        if 'email' in entry:
+            newcomers_email.append(email)
+    
+    JSON_OUT = {
+        'okay': True,
+        'stats': {
+            'code': {
+                'newcomers': newcomers_code,
+                'seen': len(code_contributors),
+            },
+            'issues': {
+                'newcomers': newcomers_issues,
+                'seen': len(issue_contributors),
+            },
+            'email': {
+                'newcomers': newcomers_email,
+                'seen': len(email_contributors),
+            }
+        },
+        'bios': newcomers,
+        'responseTime': time.time() - now
+    }
+    yield json.dumps(JSON_OUT, indent = 2)

-- 
To stop receiving notification emails like this one, please contact
"commits@kibble.apache.org" <co...@kibble.apache.org>.

[kibble] 01/06: nix svn for now - unsure how we would incorporate it

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kibble.git

commit 6fa9dbbce187544e5ee8c99c356d25d7656bc443
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Sat Jan 13 00:55:29 2018 +0100

    nix svn for now - unsure how we would incorporate it
---
 api/yaml/sourcetypes.yaml | 4 ----
 docs/source/managing.rst  | 3 ---
 2 files changed, 7 deletions(-)

diff --git a/api/yaml/sourcetypes.yaml b/api/yaml/sourcetypes.yaml
index 8ad82bd..4bb7f73 100644
--- a/api/yaml/sourcetypes.yaml
+++ b/api/yaml/sourcetypes.yaml
@@ -16,10 +16,6 @@ github:
     optauth:
         - username
         - password
-svn:
-    title: "Subversion repository"
-    regex: "https?://.+/.*"
-    example: "https://svn.apache.org/repos/asf/httpd/httpd"
 
 jira:
     title: "JIRA Project"
diff --git a/docs/source/managing.rst b/docs/source/managing.rst
index 0c0d13e..295ead5 100644
--- a/docs/source/managing.rst
+++ b/docs/source/managing.rst
@@ -89,9 +89,6 @@ JIRA
    
 Twitter
    This is a Twitter account. Currently not much done there. WIP.
-   
-SVN
-   This is a Subversion directory. It currently does nothing :(
 
 
 Once you have added the resource URLs you wish to analyse, you

-- 
To stop receiving notification emails like this one, please contact
"commits@kibble.apache.org" <co...@kibble.apache.org>.

[kibble] 05/06: fix up comstat widget, add it to the widget yaml list

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kibble.git

commit 39a75dcac37410d48e1bc7e8619a7d058658c3be
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Wed Jan 17 19:37:20 2018 +0100

    fix up comstat widget, add it to the widget yaml list
---
 api/yaml/widgets.yaml              |  31 +++++++
 ui/js/coffee/widget_comstat.coffee | 167 ++++++++++++++++++++-----------------
 2 files changed, 120 insertions(+), 78 deletions(-)

diff --git a/api/yaml/widgets.yaml b/api/yaml/widgets.yaml
index a1572ce..dedbbab 100644
--- a/api/yaml/widgets.yaml
+++ b/api/yaml/widgets.yaml
@@ -680,3 +680,34 @@ widgets:
                         source: "mail/mood-timeseries"
                         name:   "Mood over time"
                         blocks: 12
+
+## NEWTIMERS (COMSTAT)
+    comstat:
+        title: "Community Growth"
+        rows:
+            -
+                name: "Date picker row"
+                children:
+                    -
+                        type:   "datepicker"
+                        blocks: 4
+                        name:   "Date picker"
+                    -
+                        type:   "viewpicker"
+                        blocks: 4
+                        source: "views"
+                        name:   "Quick filter"
+                    -
+                        type:   sourcepicker
+                        blocks: 4
+                        source: "sources"
+                        name:   "Source picker"
+            -
+                name: "Community Growth"
+                children:
+                    -
+                        type:   "comstat"
+                        source: "bio/newtimers"
+                        name:   "New contributors"
+                        blocks: 12
+                    
\ No newline at end of file
diff --git a/ui/js/coffee/widget_comstat.coffee b/ui/js/coffee/widget_comstat.coffee
index 88013b1..2a6dfca 100644
--- a/ui/js/coffee/widget_comstat.coffee
+++ b/ui/js/coffee/widget_comstat.coffee
@@ -23,9 +23,8 @@ comstat = (json, state) ->
         if json.stats.code.seen > 0
             row = new Row()
             js = { alphaSort: true, counts: {
-                "Regulars": json.stats.code.seen - json.stats.code.newcomers - json.stats.code.returning,
-                "Newcomers": json.stats.code.newcomers,
-                "Returning": json.stats.code.returning
+                "Regulars": json.stats.code.seen - json.stats.code.newcomers.length,
+                "Newcomers": json.stats.code.newcomers.length,
                 }
             }
             widget = new Widget(4, {name: "Code contributors this period", representation: 'comstat'})
@@ -35,21 +34,26 @@ comstat = (json, state) ->
             row.inject(widget)
             donut(js, { widget: widget})
             nl = 0
-            if json.stats.code.newtbl.length and json.stats.code.newtbl.length >= 0
-                nl = json.stats.code.newtbl.length
-            stbl = new Widget(4, { name: "New code contributors (#{nl})" })
+            if json.stats.code.newcomers.length and json.stats.code.newcomers.length >= 0
+                nl = json.stats.code.newcomers.length
+            stbl = new Widget(6, { name: "New code contributors (#{nl})" })
             
             tbl = mk('table', {class: "table table-striped"})
             tr = mk('tr', {}, [
                 mk('th', {}, "Avatar"),
                 mk('th', {}, "Name",)
                 mk('th', {}, "Address"),
+                mk('th', {}, "First commit"),
                 ])
             app(tbl, tr)
             tb = new HTML('tbody')
-            for person, i in json.stats.code.newtbl
+            for person, i in json.stats.code.newcomers
+                oemail = person
+                hash = json.bios[person].code[1].id.split('/')[1]
+                repo = json.bios[person].code[1].sourceURL
+                person = json.bios[person].bio
                 if i > 6
-                    m = json.stats.code.newtbl.length - 7
+                    m = json.stats.code.newcomers.length - 7
                     tr = mk('tr', {scope: 'row'}, [
                         mk('td', {colspan: "3"}, "+#{m} more...")
                         ])
@@ -57,8 +61,9 @@ comstat = (json, state) ->
                     break
                 tr = mk('tr', {scope: 'row'}, [
                     mk('td', {}, new HTML('img', {style: { width: '32px', height: '32px'}, class: "img-circle img-responsive", src:"https://secure.gravatar.com/avatar/#{person.md5}.png?d=identicon"})),
-                    mk('td', {}, mk('a', { href: "?page=people&email=#{person.address}"}, person.name)),
-                    mk('td', {}, person.address),
+                    mk('td', {}, mk('a', { href: "?page=people&email=#{oemail}"}, person.name)),
+                    mk('td', {}, oemail),
+                    mk('td', {}, "#{repo} / #{hash}"),
                     ])
                 tb.inject(tr)
             app(tbl, tb)
@@ -79,9 +84,8 @@ comstat = (json, state) ->
         if json.stats.issues.seen > 0
             row = new Row()
             js = { alphaSort: true, counts: {
-                "Regulars": json.stats.issues.seen - json.stats.issues.newcomers - json.stats.issues.returning,
-                "Newcomers": json.stats.issues.newcomers,
-                "Returning": json.stats.issues.returning
+                "Regulars": json.stats.issues.seen - json.stats.issues.newcomers.length,
+                "Newcomers": json.stats.issues.newcomers.length
                 }
             }
             widget = new Widget(4, {name: "Issue contributors this period", representation: 'comstat'})
@@ -91,30 +95,37 @@ comstat = (json, state) ->
             row.inject(widget)
             donut(js, { widget: widget})
             nl = 0
-            if json.stats.issues.newtbl.length and json.stats.issues.newtbl.length >= 0
-                nl = json.stats.issues.newtbl.length
-            stbl = new Widget(4, { name: "New issue contributors (#{nl})" })
+            if json.stats.issues.newcomers.length and json.stats.issues.newcomers.length >= 0
+                nl = json.stats.issues.newcomers.length
+            stbl = new Widget(6, { name: "New issue contributors (#{nl})" })
             
             tbl = mk('table', {class: "table table-striped"})
             tr = mk('tr', {}, [
                 mk('th', {}, "Avatar"),
                 mk('th', {}, "Name",)
                 mk('th', {}, "Address"),
+                mk('th', {}, "First issue"),
                 ])
             app(tbl, tr)
             tb = new HTML('tbody')
-            for person, i in json.stats.issues.newtbl
+            for person, i in json.stats.issues.newcomers
+                oemail = person
+                url = json.bios[person].issue[1].sourceURL
+                key = json.bios[person].issue[1].key || url
+                person = json.bios[person].bio
                 if i > 6
-                    m = json.stats.issues.newtbl.length - 7
+                    m = json.stats.issues.newcomers.length - 7
                     tr = mk('tr', {scope: 'row'}, [
                         mk('td', {colspan: "3"}, "+#{m} more...")
                         ])
                     tb.inject(tr)
                     break
+                
                 tr = mk('tr', {scope: 'row'}, [
                     mk('td', {}, new HTML('img', {style: { width: '32px', height: '32px'}, class: "img-circle img-responsive", src:"https://secure.gravatar.com/avatar/#{person.md5}.png?d=identicon"})),
-                    mk('td', {}, mk('a', { href: "?page=people&email=#{person.address}"}, person.name)),
-                    mk('td', {}, person.address),
+                    mk('td', {}, mk('a', { href: "?page=people&email=#{oemail}"}, person.name)),
+                    mk('td', {}, oemail),
+                    mk('td', {}, mk('a', { href: url||"#"}, txt(key))),
                     ])
                 tb.inject(tr)
             app(tbl, tb)
@@ -122,7 +133,7 @@ comstat = (json, state) ->
             row.inject(stbl)
             
             if json.stats.issues.timeseries and json.stats.issues.timeseries.length > 0
-                widget = new Widget(4, {name: "New issue contributors over time:", representation: 'bars'})
+                widget = new Widget(6, {name: "New issue contributors over time:", representation: 'bars'})
                 widget.parent = state.widget
                 row.inject(widget)
                 js = {widgetType: { chartType: 'bar'}, timeseries: json.stats.issues.timeseries}
@@ -132,66 +143,66 @@ comstat = (json, state) ->
             
             
             state.widget.inject(row.div)
-            
-        if json.stats.converts.issue_to_code.length and json.stats.converts.issue_to_code.length > 0
-            row = new Row()
-            
-            stbl = new Widget(6, { name: "Previous issue contributors who are now contributing code:" })
-            
-            tbl = mk('table', {class: "table table-striped"})
-            tr = mk('tr', {}, [
-                mk('th', {}, "Avatar"),
-                mk('th', {}, "Name",)
-                mk('th', {}, "Address"),
-                mk('th', {}, "Days from first issue to first code contribution:"),
-                ])
-            app(tbl, tr)
-            tb = new HTML('tbody')
-            for person, i in json.stats.converts.issue_to_code
-                if i > 20
-                    break
-                tr = mk('tr', {scope: 'row'}, [
-                    mk('td', {}, new HTML('img', {style: { width: '32px', height: '32px'}, class: "img-circle img-responsive", src:"https://secure.gravatar.com/avatar/#{person.md5}.png?d=identicon"})),
-                    mk('td', {}, mk('a', { href: "?page=people&email=#{person.address}"}, person.name)),
-                    mk('td', {}, person.address),
-                    mk('td', {style: { textAlign: 'right'}}, (Math.floor(person.tdiff / (86400))).pretty()),
+        if json.stats.converts
+            if json.stats.converts.issue_to_code.length and json.stats.converts.issue_to_code.length > 0
+                row = new Row()
+                
+                stbl = new Widget(6, { name: "Previous issue contributors who are now contributing code:" })
+                
+                tbl = mk('table', {class: "table table-striped"})
+                tr = mk('tr', {}, [
+                    mk('th', {}, "Avatar"),
+                    mk('th', {}, "Name",)
+                    mk('th', {}, "Address"),
+                    mk('th', {}, "Days from first issue to first code contribution:"),
                     ])
-                tb.inject(tr)
-            app(tbl, tb)
-            stbl.inject(tbl)
-            row.inject(stbl)
-            
-            state.widget.inject(row.div)
-        
-        if json.stats.converts.email_to_code.length and json.stats.converts.email_to_code.length > 0
-            row = new Row()
-            
-            stbl = new Widget(6, { name: "Previous email authors who are now contributing code:" })
+                app(tbl, tr)
+                tb = new HTML('tbody')
+                for person, i in json.stats.converts.issue_to_code
+                    if i > 20
+                        break
+                    tr = mk('tr', {scope: 'row'}, [
+                        mk('td', {}, new HTML('img', {style: { width: '32px', height: '32px'}, class: "img-circle img-responsive", src:"https://secure.gravatar.com/avatar/#{person.md5}.png?d=identicon"})),
+                        mk('td', {}, mk('a', { href: "?page=people&email=#{person.address}"}, person.name)),
+                        mk('td', {}, person.address),
+                        mk('td', {style: { textAlign: 'right'}}, (Math.floor(person.tdiff / (86400))).pretty()),
+                        ])
+                    tb.inject(tr)
+                app(tbl, tb)
+                stbl.inject(tbl)
+                row.inject(stbl)
+                
+                state.widget.inject(row.div)
             
-            tbl = mk('table', {class: "table table-striped"})
-            tr = mk('tr', {}, [
-                mk('th', {}, "Avatar"),
-                mk('th', {}, "Name",)
-                mk('th', {}, "Address"),
-                mk('th', {}, "Days from first email to first code contribution:"),
-                ])
-            app(tbl, tr)
-            tb = new HTML('tbody')
-            for person, i in json.stats.converts.email_to_code
-                if i > 20
-                    break
-                tr = mk('tr', {scope: 'row'}, [
-                    mk('td', {}, new HTML('img', {style: { width: '32px', height: '32px'}, class: "img-circle img-responsive", src:"https://secure.gravatar.com/avatar/#{person.md5}.png?d=identicon"})),
-                    mk('td', {}, mk('a', { href: "?page=people&email=#{person.address}"}, person.name)),
-                    mk('td', {}, person.address),
-                    mk('td', {style: { textAlign: 'right'}}, (Math.floor(person.tdiff / (86400))).pretty()),
+            if json.stats.converts.email_to_code.length and json.stats.converts.email_to_code.length > 0
+                row = new Row()
+                
+                stbl = new Widget(6, { name: "Previous email authors who are now contributing code:" })
+                
+                tbl = mk('table', {class: "table table-striped"})
+                tr = mk('tr', {}, [
+                    mk('th', {}, "Avatar"),
+                    mk('th', {}, "Name",)
+                    mk('th', {}, "Address"),
+                    mk('th', {}, "Days from first email to first code contribution:"),
                     ])
-                tb.inject(tr)
-            app(tbl, tb)
-            stbl.inject(tbl)
-            row.inject(stbl)
-            
-            state.widget.inject(row.div)
+                app(tbl, tr)
+                tb = new HTML('tbody')
+                for person, i in json.stats.converts.email_to_code
+                    if i > 20
+                        break
+                    tr = mk('tr', {scope: 'row'}, [
+                        mk('td', {}, new HTML('img', {style: { width: '32px', height: '32px'}, class: "img-circle img-responsive", src:"https://secure.gravatar.com/avatar/#{person.md5}.png?d=identicon"})),
+                        mk('td', {}, mk('a', { href: "?page=people&email=#{person.address}"}, person.name)),
+                        mk('td', {}, person.address),
+                        mk('td', {style: { textAlign: 'right'}}, (Math.floor(person.tdiff / (86400))).pretty()),
+                        ])
+                    tb.inject(tr)
+                app(tbl, tb)
+                stbl.inject(tbl)
+                row.inject(stbl)
+                
+                state.widget.inject(row.div)
     else
         notice = new HTML('h2', {}, "Community growth stats only works with user-defined views!")
         p = new HTML('p', {}, "To see community growth stats, please create a view of the code, email, bugs you wish to view stats for, or select an existng view in the list above")

-- 
To stop receiving notification emails like this one, please contact
"commits@kibble.apache.org" <co...@kibble.apache.org>.

[kibble] 04/06: regen openapi specs

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kibble.git

commit e335c4b73cee536d2d51f4f3be6a218c7850d511
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Wed Jan 17 19:37:00 2018 +0100

    regen openapi specs
    
    this is a bit wrong, WIP
---
 api/yaml/openapi.yaml | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/api/yaml/openapi.yaml b/api/yaml/openapi.yaml
index 6a903ac..4e4a535 100644
--- a/api/yaml/openapi.yaml
+++ b/api/yaml/openapi.yaml
@@ -665,6 +665,46 @@ paths:
       security:
       - cookieAuth: []
       summary: Shows some facts about a contributor
+  /api/bio/newtimers:
+    get:
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Biography'
+          description: 200 Response
+        default:
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+          description: unexpected error
+      security:
+      - cookieAuth: []
+      summary: Shows some facts about a contributor
+    post:
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/defaultWidgetArgs'
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Biography'
+          description: 200 Response
+        default:
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+          description: unexpected error
+      security:
+      - cookieAuth: []
+      summary: Shows some facts about a contributor
   /api/bio/trends:
     get:
       responses:

-- 
To stop receiving notification emails like this one, please contact
"commits@kibble.apache.org" <co...@kibble.apache.org>.

[kibble] 06/06: regen JS

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kibble.git

commit 48f3e58c9cf4621dd60b396adb2469c82b793e7a
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Wed Jan 17 19:37:26 2018 +0100

    regen JS
---
 ui/js/kibble.v1.js | 300 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 171 insertions(+), 129 deletions(-)

diff --git a/ui/js/kibble.v1.js b/ui/js/kibble.v1.js
index 799938f..9daf1fb 100644
--- a/ui/js/kibble.v1.js
+++ b/ui/js/kibble.v1.js
@@ -1,5 +1,5 @@
-// Generated by CoffeeScript 1.9.3
-var API, APIVERSION, Chart, HTML, Row, Widget, aSourceTypes, accountCallback, addSourceType, addSources, addorguser, addsources, affiliate, affiliation, affiliationWizard, altemail, app, badModal, bio, chartOnclick, chartToSvg, chartWrapperButtons, charts_donutchart, charts_gaugechart, charts_linechart, charts_linechart_stacked, charts_linked, charts_radarchart, cog, comstat, copyCSS, currentSources, dataTable, datepicker, datepickers, defaultOrgChanged, deletesource, doResetPass, donut, [...]
+// Generated by CoffeeScript 1.10.0
+var API, APIVERSION, Chart, HTML, Row, Widget, aSourceTypes, accountCallback, addSourceType, addSources, addorguser, addsources, affiliate, affiliation, affiliationWizard, altemail, app, badModal, bio, chartOnclick, chartToSvg, chartWrapperButtons, charts_donutchart, charts_gaugechart, charts_linechart, charts_linechart_stacked, charts_linked, charts_radarchart, cog, comstat, copyCSS, currentSources, dataTable, datepicker, datepickers, defaultOrgChanged, deletesource, doResetPass, donut, [...]
   indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
 
 signup = function(form) {
@@ -953,7 +953,7 @@ copyCSS = function(destination, source) {
 };
 
 downloadBlob = function(name, uri) {
-  var blob, e, saveLink, url;
+  var blob, e, error, saveLink, url;
   if (navigator.msSaveOrOpenBlob) {
     return navigator.msSaveOrOpenBlob(uriToBlob(uri), name);
   } else {
@@ -970,8 +970,8 @@ downloadBlob = function(name, uri) {
           return URL.revokeObjectURL(url);
         });
       };
-    } catch (_error) {
-      e = _error;
+    } catch (error) {
+      e = error;
       console.warn('This browser does not support object URLs. Falling back to string URL.');
       saveLink.href = uri;
     }
@@ -1455,7 +1455,11 @@ updateTimeseriesWidgets = function(range) {
       to: to,
       from: from
     });
-    return updateWidgets('worldmap', null, {
+    updateWidgets('worldmap', null, {
+      to: to,
+      from: from
+    });
+    return updateWidgets('jsondump', null, {
       to: to,
       from: from
     });
@@ -1660,7 +1664,10 @@ explorer = function(json, state) {
     updateWidgets('mvp', null, {
       source: source
     });
-    return updateWidgets('comstat', null, {
+    updateWidgets('comstat', null, {
+      source: source
+    });
+    return updateWidgets('jsondump', null, {
       source: source
     });
   });
@@ -1706,7 +1713,10 @@ explorer = function(json, state) {
     updateWidgets('mvp', null, {
       author: author
     });
-    return updateWidgets('comstat', null, {
+    updateWidgets('comstat', null, {
+      author: author
+    });
+    return updateWidgets('jsondump', null, {
       author: author
     });
   });
@@ -1809,9 +1819,12 @@ sourceexplorer = function(json, state) {
     updateWidgets('mvp', null, {
       source: source
     });
-    return updateWidgets('comstat', null, {
+    updateWidgets('comstat', null, {
       source: source
     });
+    return updateWidgets('jsondump', null, {
+      author: author
+    });
   });
 };
 
@@ -2274,6 +2287,7 @@ subFilter = function() {
   updateWidgets('mvp', null, x);
   updateWidgets('comstat', null, x);
   updateWidgets('worldmap', null, x);
+  updateWidgets('jsondump', null, x);
   return $("a").each(function() {
     var m, url;
     url = $(this).attr('href');
@@ -2367,6 +2381,7 @@ viewexplorer = function(json, state) {
     updateWidgets('mvp', null, x);
     updateWidgets('comstat', null, x);
     updateWidgets('worldmap', null, x);
+    updateWidgets('jsondump', null, x);
     return $("a").each(function() {
       var m, url;
       url = $(this).attr('href');
@@ -2863,7 +2878,7 @@ fetch = function(url, xstate, callback, nocreds) {
   xmlHttp.open("GET", "api/" + url, true);
   xmlHttp.send(null);
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, mpart, response;
+    var e, error, js, mpart, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -2884,8 +2899,8 @@ fetch = function(url, xstate, callback, nocreds) {
         try {
           response = JSON.parse(xmlHttp.responseText);
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -2910,7 +2925,7 @@ put = function(url, json, xstate, callback, nocreds) {
   xmlHttp.open("PUT", "api/" + url, true);
   xmlHttp.send(JSON.stringify(json || {}));
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, response;
+    var e, error, js, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -2931,8 +2946,8 @@ put = function(url, json, xstate, callback, nocreds) {
             return;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -2957,7 +2972,7 @@ patch = function(url, json, xstate, callback, nocreds) {
   xmlHttp.open("PATCH", "api/" + url, true);
   xmlHttp.send(JSON.stringify(json || {}));
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, response;
+    var e, error, js, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -2978,8 +2993,8 @@ patch = function(url, json, xstate, callback, nocreds) {
             return;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -3004,7 +3019,7 @@ xdelete = function(url, json, xstate, callback, nocreds) {
   xmlHttp.open("DELETE", "api/" + url, true);
   xmlHttp.send(JSON.stringify(json || {}));
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, response;
+    var e, error, js, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -3025,8 +3040,8 @@ xdelete = function(url, json, xstate, callback, nocreds) {
             return;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -3062,7 +3077,7 @@ post = function(url, json, xstate, callback, snap) {
   xmlHttp.setRequestHeader("Content-type", "application/json");
   xmlHttp.send(fdata);
   return xmlHttp.onreadystatechange = function(state) {
-    var e, response;
+    var e, error, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -3076,8 +3091,8 @@ post = function(url, json, xstate, callback, snap) {
             xstate.widget.json = response;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -3668,6 +3683,9 @@ setupPage = function(json, state) {
           case 'membership':
             results1.push(widget.load(membershipList));
             break;
+          case 'jsondump':
+            results1.push(widget.load(jsondump));
+            break;
           default:
             results1.push(void 0);
         }
@@ -4353,7 +4371,7 @@ sourceadd = function(json, state) {
     div.inject(opt);
     div.inject(lbl);
     obj.inject(new HTML('p', {}, el.description || ""));
-    obj.inject(keyValueForm('textarea', 'source', 'Source URL:', "For example: " + el.example + ". You can add multiple sources, one per line."));
+    obj.inject(keyValueForm('textarea', 'source', 'Source URL/ID:', "For example: " + el.example + ". You can add multiple sources, one per line."));
     if (el.optauth) {
       obj.inject((el.authrequired ? "Required" : "Optional") + " authentication options:");
       ref = el.optauth;
@@ -5054,6 +5072,9 @@ updateWidgets = function(type, target, eargs) {
         case 'worldmap':
           results.push(widget.load(worldmap));
           break;
+        case 'jsondump':
+          results.push(widget.load(jsondump));
+          break;
         default:
           results.push(void 0);
       }
@@ -5282,7 +5303,7 @@ Row = (function() {
 })();
 
 comstat = function(json, state) {
-  var aa, ab, chk, i, js, lb, len, len1, len2, len3, m, nl, notice, p, person, q, ref, ref1, ref2, ref3, row, stbl, tb, tbl, tr, u, widget;
+  var aa, ab, chk, hash, i, js, key, lb, len, len1, len2, len3, m, nl, notice, oemail, p, person, q, ref, ref1, ref2, ref3, repo, row, stbl, tb, tbl, tr, u, url, widget;
   if (json && json.stats) {
     row = new Row();
     p = new HTML('p', {}, globArgs.committersOnly === 'true' ? "You are currently only seeing stats for committers. To view statistics for all contributors (committers and authors), please uncheck the box below:" : "You are currently seeing stats for both committership and authorship of code. To view only committership stats, tick the box below:");
@@ -5304,9 +5325,8 @@ comstat = function(json, state) {
       js = {
         alphaSort: true,
         counts: {
-          "Regulars": json.stats.code.seen - json.stats.code.newcomers - json.stats.code.returning,
-          "Newcomers": json.stats.code.newcomers,
-          "Returning": json.stats.code.returning
+          "Regulars": json.stats.code.seen - json.stats.code.newcomers.length,
+          "Newcomers": json.stats.code.newcomers.length
         }
       };
       widget = new Widget(4, {
@@ -5321,23 +5341,27 @@ comstat = function(json, state) {
         widget: widget
       });
       nl = 0;
-      if (json.stats.code.newtbl.length && json.stats.code.newtbl.length >= 0) {
-        nl = json.stats.code.newtbl.length;
+      if (json.stats.code.newcomers.length && json.stats.code.newcomers.length >= 0) {
+        nl = json.stats.code.newcomers.length;
       }
-      stbl = new Widget(4, {
+      stbl = new Widget(6, {
         name: "New code contributors (" + nl + ")"
       });
       tbl = mk('table', {
         "class": "table table-striped"
       });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address")]);
+      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "First commit")]);
       app(tbl, tr);
       tb = new HTML('tbody');
-      ref = json.stats.code.newtbl;
+      ref = json.stats.code.newcomers;
       for (i = q = 0, len = ref.length; q < len; i = ++q) {
         person = ref[i];
+        oemail = person;
+        hash = json.bios[person].code[1].id.split('/')[1];
+        repo = json.bios[person].code[1].sourceURL;
+        person = json.bios[person].bio;
         if (i > 6) {
-          m = json.stats.code.newtbl.length - 7;
+          m = json.stats.code.newcomers.length - 7;
           tr = mk('tr', {
             scope: 'row'
           }, [
@@ -5359,8 +5383,8 @@ comstat = function(json, state) {
             "class": "img-circle img-responsive",
             src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
           })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address)
+            href: "?page=people&email=" + oemail
+          }, person.name)), mk('td', {}, oemail), mk('td', {}, repo + " / " + hash)
         ]);
         tb.inject(tr);
       }
@@ -5393,9 +5417,8 @@ comstat = function(json, state) {
       js = {
         alphaSort: true,
         counts: {
-          "Regulars": json.stats.issues.seen - json.stats.issues.newcomers - json.stats.issues.returning,
-          "Newcomers": json.stats.issues.newcomers,
-          "Returning": json.stats.issues.returning
+          "Regulars": json.stats.issues.seen - json.stats.issues.newcomers.length,
+          "Newcomers": json.stats.issues.newcomers.length
         }
       };
       widget = new Widget(4, {
@@ -5410,23 +5433,27 @@ comstat = function(json, state) {
         widget: widget
       });
       nl = 0;
-      if (json.stats.issues.newtbl.length && json.stats.issues.newtbl.length >= 0) {
-        nl = json.stats.issues.newtbl.length;
+      if (json.stats.issues.newcomers.length && json.stats.issues.newcomers.length >= 0) {
+        nl = json.stats.issues.newcomers.length;
       }
-      stbl = new Widget(4, {
+      stbl = new Widget(6, {
         name: "New issue contributors (" + nl + ")"
       });
       tbl = mk('table', {
         "class": "table table-striped"
       });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address")]);
+      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "First issue")]);
       app(tbl, tr);
       tb = new HTML('tbody');
-      ref1 = json.stats.issues.newtbl;
+      ref1 = json.stats.issues.newcomers;
       for (i = u = 0, len1 = ref1.length; u < len1; i = ++u) {
         person = ref1[i];
+        oemail = person;
+        url = json.bios[person].issue[1].sourceURL;
+        key = json.bios[person].issue[1].key || url;
+        person = json.bios[person].bio;
         if (i > 6) {
-          m = json.stats.issues.newtbl.length - 7;
+          m = json.stats.issues.newcomers.length - 7;
           tr = mk('tr', {
             scope: 'row'
           }, [
@@ -5448,8 +5475,10 @@ comstat = function(json, state) {
             "class": "img-circle img-responsive",
             src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
           })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address)
+            href: "?page=people&email=" + oemail
+          }, person.name)), mk('td', {}, oemail), mk('td', {}, mk('a', {
+            href: url || "#"
+          }, txt(key)))
         ]);
         tb.inject(tr);
       }
@@ -5457,7 +5486,7 @@ comstat = function(json, state) {
       stbl.inject(tbl);
       row.inject(stbl);
       if (json.stats.issues.timeseries && json.stats.issues.timeseries.length > 0) {
-        widget = new Widget(4, {
+        widget = new Widget(6, {
           name: "New issue contributors over time:",
           representation: 'bars'
         });
@@ -5477,89 +5506,91 @@ comstat = function(json, state) {
       }
       state.widget.inject(row.div);
     }
-    if (json.stats.converts.issue_to_code.length && json.stats.converts.issue_to_code.length > 0) {
-      row = new Row();
-      stbl = new Widget(6, {
-        name: "Previous issue contributors who are now contributing code:"
-      });
-      tbl = mk('table', {
-        "class": "table table-striped"
-      });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first issue to first code contribution:")]);
-      app(tbl, tr);
-      tb = new HTML('tbody');
-      ref2 = json.stats.converts.issue_to_code;
-      for (i = aa = 0, len2 = ref2.length; aa < len2; i = ++aa) {
-        person = ref2[i];
-        if (i > 20) {
-          break;
+    if (json.stats.converts) {
+      if (json.stats.converts.issue_to_code.length && json.stats.converts.issue_to_code.length > 0) {
+        row = new Row();
+        stbl = new Widget(6, {
+          name: "Previous issue contributors who are now contributing code:"
+        });
+        tbl = mk('table', {
+          "class": "table table-striped"
+        });
+        tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first issue to first code contribution:")]);
+        app(tbl, tr);
+        tb = new HTML('tbody');
+        ref2 = json.stats.converts.issue_to_code;
+        for (i = aa = 0, len2 = ref2.length; aa < len2; i = ++aa) {
+          person = ref2[i];
+          if (i > 20) {
+            break;
+          }
+          tr = mk('tr', {
+            scope: 'row'
+          }, [
+            mk('td', {}, new HTML('img', {
+              style: {
+                width: '32px',
+                height: '32px'
+              },
+              "class": "img-circle img-responsive",
+              src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
+            })), mk('td', {}, mk('a', {
+              href: "?page=people&email=" + person.address
+            }, person.name)), mk('td', {}, person.address), mk('td', {
+              style: {
+                textAlign: 'right'
+              }
+            }, (Math.floor(person.tdiff / 86400.)).pretty())
+          ]);
+          tb.inject(tr);
         }
-        tr = mk('tr', {
-          scope: 'row'
-        }, [
-          mk('td', {}, new HTML('img', {
-            style: {
-              width: '32px',
-              height: '32px'
-            },
-            "class": "img-circle img-responsive",
-            src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
-          })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address), mk('td', {
-            style: {
-              textAlign: 'right'
-            }
-          }, (Math.floor(person.tdiff / 86400.)).pretty())
-        ]);
-        tb.inject(tr);
-      }
-      app(tbl, tb);
-      stbl.inject(tbl);
-      row.inject(stbl);
-      state.widget.inject(row.div);
-    }
-    if (json.stats.converts.email_to_code.length && json.stats.converts.email_to_code.length > 0) {
-      row = new Row();
-      stbl = new Widget(6, {
-        name: "Previous email authors who are now contributing code:"
-      });
-      tbl = mk('table', {
-        "class": "table table-striped"
-      });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first email to first code contribution:")]);
-      app(tbl, tr);
-      tb = new HTML('tbody');
-      ref3 = json.stats.converts.email_to_code;
-      for (i = ab = 0, len3 = ref3.length; ab < len3; i = ++ab) {
-        person = ref3[i];
-        if (i > 20) {
-          break;
+        app(tbl, tb);
+        stbl.inject(tbl);
+        row.inject(stbl);
+        state.widget.inject(row.div);
+      }
+      if (json.stats.converts.email_to_code.length && json.stats.converts.email_to_code.length > 0) {
+        row = new Row();
+        stbl = new Widget(6, {
+          name: "Previous email authors who are now contributing code:"
+        });
+        tbl = mk('table', {
+          "class": "table table-striped"
+        });
+        tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first email to first code contribution:")]);
+        app(tbl, tr);
+        tb = new HTML('tbody');
+        ref3 = json.stats.converts.email_to_code;
+        for (i = ab = 0, len3 = ref3.length; ab < len3; i = ++ab) {
+          person = ref3[i];
+          if (i > 20) {
+            break;
+          }
+          tr = mk('tr', {
+            scope: 'row'
+          }, [
+            mk('td', {}, new HTML('img', {
+              style: {
+                width: '32px',
+                height: '32px'
+              },
+              "class": "img-circle img-responsive",
+              src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
+            })), mk('td', {}, mk('a', {
+              href: "?page=people&email=" + person.address
+            }, person.name)), mk('td', {}, person.address), mk('td', {
+              style: {
+                textAlign: 'right'
+              }
+            }, (Math.floor(person.tdiff / 86400.)).pretty())
+          ]);
+          tb.inject(tr);
         }
-        tr = mk('tr', {
-          scope: 'row'
-        }, [
-          mk('td', {}, new HTML('img', {
-            style: {
-              width: '32px',
-              height: '32px'
-            },
-            "class": "img-circle img-responsive",
-            src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
-          })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address), mk('td', {
-            style: {
-              textAlign: 'right'
-            }
-          }, (Math.floor(person.tdiff / 86400.)).pretty())
-        ]);
-        tb.inject(tr);
+        app(tbl, tb);
+        stbl.inject(tbl);
+        row.inject(stbl);
+        return state.widget.inject(row.div);
       }
-      app(tbl, tb);
-      stbl.inject(tbl);
-      row.inject(stbl);
-      return state.widget.inject(row.div);
     }
   } else {
     notice = new HTML('h2', {}, "Community growth stats only works with user-defined views!");
@@ -5737,6 +5768,17 @@ factors = function(json, state) {
   }
 };
 
+jsondump = function(json, state) {
+  var pre;
+  pre = new HTML('pre', {
+    style: {
+      whiteSpace: 'pre-wrap'
+    }
+  });
+  pre.inject(JSON.stringify(json, null, 2));
+  return state.widget.inject(pre, true);
+};
+
 linechart = function(json, state) {
   var aa, ab, cat, catdata, cats, catseries, chartBox, chk, dates, div, filled, from, id, item, key, label, len, len1, len2, len3, list, m, opt, point, q, range, ref, ref1, ref2, ref3, rv, stack, tName, to, type, u, val;
   div = document.createElement('div');

-- 
To stop receiving notification emails like this one, please contact
"commits@kibble.apache.org" <co...@kibble.apache.org>.

[kibble] 02/06: Add in a chepa json dump widget for debugging

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kibble.git

commit cdfbe837d819fd2c0033bddbae0953bfc2aca473
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Wed Jan 17 19:36:01 2018 +0100

    Add in a chepa json dump widget for debugging
---
 ui/js/coffee/datepicker.coffee      | 1 +
 ui/js/coffee/explorer.coffee        | 5 +++++
 ui/js/coffee/pageloader.coffee      | 1 +
 ui/js/coffee/widget.coffee          | 1 +
 ui/js/coffee/widget_jsondump.coffee | 5 +++++
 5 files changed, 13 insertions(+)

diff --git a/ui/js/coffee/datepicker.coffee b/ui/js/coffee/datepicker.coffee
index 4464a64..5250679 100644
--- a/ui/js/coffee/datepicker.coffee
+++ b/ui/js/coffee/datepicker.coffee
@@ -36,6 +36,7 @@ updateTimeseriesWidgets = (range) ->
             updateWidgets('mvp', null, { to: to, from: from})
             updateWidgets('comstat', null, { to: to, from: from})
             updateWidgets('worldmap', null, { to: to, from: from})
+            updateWidgets('jsondump', null, { to: to, from: from})
                 
 datepicker = (widget) ->
         div = document.createElement('div')
diff --git a/ui/js/coffee/explorer.coffee b/ui/js/coffee/explorer.coffee
index 99d2fde..61f0411 100644
--- a/ui/js/coffee/explorer.coffee
+++ b/ui/js/coffee/explorer.coffee
@@ -64,6 +64,7 @@ explorer = (json, state) ->
                 updateWidgets('trends', null, { source: source })
                 updateWidgets('mvp', null, { source: source })
                 updateWidgets('comstat', null, { source: source })
+                updateWidgets('jsondump', null, { source: source })
               )
         
         
@@ -92,6 +93,7 @@ explorer = (json, state) ->
                 updateWidgets('relationship', null, {author: author})
                 updateWidgets('mvp', null, {author: author})
                 updateWidgets('comstat', null, { author: author })
+                updateWidgets('jsondump', null, { author: author })
                 )
         state.widget.inject(chk)
         label = document.createElement('label')
@@ -155,6 +157,7 @@ sourceexplorer = (json, state) ->
                 updateWidgets('trends', null, { source: source })
                 updateWidgets('mvp', null, { source: source })
                 updateWidgets('comstat', null, { source: source })
+                updateWidgets('jsondump', null, { author: author })
         )
 
 
@@ -463,6 +466,7 @@ subFilter = () ->
         updateWidgets('mvp', null, x)
         updateWidgets('comstat', null, x)
         updateWidgets('worldmap', null, x)
+        updateWidgets('jsondump', null, x)
         
         $( "a" ).each( () ->
             url = $(this).attr('href')
@@ -537,6 +541,7 @@ viewexplorer = (json, state) ->
                 updateWidgets('mvp', null, x)
                 updateWidgets('comstat', null, x)
                 updateWidgets('worldmap', null, x)
+                updateWidgets('jsondump', null, x)
                 
                 $( "a" ).each( () ->
                     url = $(this).attr('href')
diff --git a/ui/js/coffee/pageloader.coffee b/ui/js/coffee/pageloader.coffee
index fe00cca..9938b6b 100644
--- a/ui/js/coffee/pageloader.coffee
+++ b/ui/js/coffee/pageloader.coffee
@@ -108,6 +108,7 @@ setupPage = (json, state) ->
                 when 'worldmap' then widget.load(worldmap)
                 when 'orglist' then widget.load(orglist)
                 when 'membership' then widget.load(membershipList)
+                when 'jsondump' then widget.load(jsondump)
 
 
 
diff --git a/ui/js/coffee/widget.coffee b/ui/js/coffee/widget.coffee
index b46afab..b8f672a 100644
--- a/ui/js/coffee/widget.coffee
+++ b/ui/js/coffee/widget.coffee
@@ -133,6 +133,7 @@ updateWidgets = (type, target, eargs) ->
                 when 'mvp' then widget.load(mvp)
                 when 'comstat' then widget.load(comstat)
                 when 'worldmap' then widget.load(worldmap)
+                when 'jsondump' then widget.load(jsondump)
 
 class pubWidget
     constructor: (@div, @wid, @config) ->
diff --git a/ui/js/coffee/widget_jsondump.coffee b/ui/js/coffee/widget_jsondump.coffee
new file mode 100644
index 0000000..8715b73
--- /dev/null
+++ b/ui/js/coffee/widget_jsondump.coffee
@@ -0,0 +1,5 @@
+jsondump = (json, state) ->
+    pre = new HTML('pre', { style: { whiteSpace: 'pre-wrap'}})
+    pre.inject(JSON.stringify(json, null, 2))
+    state.widget.inject(pre, true)
+

-- 
To stop receiving notification emails like this one, please contact
"commits@kibble.apache.org" <co...@kibble.apache.org>.