[ARVADOS] updated: 2220f7f54be3445457a82c71e1e60d6492ede3a3

Git user git at public.curoverse.com
Thu Aug 10 14:57:01 EDT 2017


Summary of changes:
 .../assets/javascripts/components/collections.js   |  82 +++++---------
 .../app/assets/javascripts/models/loader.js        | 126 +++++++++++++++++++++
 2 files changed, 152 insertions(+), 56 deletions(-)
 create mode 100644 apps/workbench/app/assets/javascripts/models/loader.js

       via  2220f7f54be3445457a82c71e1e60d6492ede3a3 (commit)
       via  2014757448a9ce52f2aa4f6af4ce2284c6858bb5 (commit)
      from  473c95bec9a11808bb286528a51a4dd671e1d0bb (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 2220f7f54be3445457a82c71e1e60d6492ede3a3
Author: Tom Clegg <tom at curoverse.com>
Date:   Thu Aug 10 14:12:33 2017 -0400

    12033: Extract multisite loader to its own class.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at curoverse.com>

diff --git a/apps/workbench/app/assets/javascripts/components/collections.js b/apps/workbench/app/assets/javascripts/components/collections.js
index 9334bcc..527ce6c 100644
--- a/apps/workbench/app/assets/javascripts/components/collections.js
+++ b/apps/workbench/app/assets/javascripts/components/collections.js
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 window.components = window.components || {}
-window.components.collection_table_narrow = {
+window.components.collection_table = {
     view: function(vnode) {
         return m('table.table.table-condensed', [
             m('thead', m('tr', [
@@ -13,7 +13,7 @@ window.components.collection_table_narrow = {
                 m('th', 'last modified'),
             ])),
             m('tbody', [
-                vnode.attrs.results.displayable.map(function(item) {
+                vnode.attrs.loader.displayable.map(function(item) {
                     return m('tr', [
                         m('td', m('a.btn.btn-xs.btn-default', {href: item.session.baseURL.replace('://', '://workbench.')+'/collections/'+item.uuid}, 'Show')),
                         m('td', item.uuid),
@@ -24,149 +24,42 @@ window.components.collection_table_narrow = {
             ]),
             m('tfoot', m('tr', [
                 m('th[colspan=4]', m('button.btn.btn-xs', {
-                    className: vnode.attrs.results.loadMore ? 'btn-primary' : 'btn-default',
+                    className: vnode.attrs.loader.loadMore ? 'btn-primary' : 'btn-default',
                     style: {
                         display: 'block',
                         width: '12em',
                         marginLeft: 'auto',
                         marginRight: 'auto',
                     },
-                    disabled: !vnode.attrs.results.loadMore,
+                    disabled: !vnode.attrs.loader.loadMore,
                     onclick: function() {
-                        vnode.attrs.results.loadMore()
+                        vnode.attrs.loader.loadMore()
                         return false
                     },
-                }, vnode.attrs.results.loadMore ? 'Load more' : '(loading)')),
+                }, vnode.attrs.loader.loadMore ? 'Load more' : '(loading)')),
             ])),
         ])
     },
 }
 
-function Pager(loadFunc) {
-    // loadFunc(filters) returns a promise for a page of results.
-    var pager = this
-    Object.assign(pager, {
-        done: false,
-        items: m.stream(),
-        thresholdItem: null,
-        loadNextPage: function() {
-            // Get the next page, if there are any more items to get.
-            if (pager.done)
-                return
-            var filters = pager.thresholdItem ? [
-                ["modified_at", "<=", pager.thresholdItem.modified_at],
-                ["uuid", "!=", pager.thresholdItem.uuid],
-            ] : []
-            loadFunc(filters).then(function(resp) {
-                var items = pager.items() || []
-                Array.prototype.push.apply(items, resp.items)
-                if (resp.items.length == 0)
-                    pager.done = true
-                else
-                    pager.thresholdItem = resp.items[resp.items.length-1]
-                pager.items(items)
-            })
-        },
-    })
-}
-
 window.components.collection_search = {
     oninit: function(vnode) {
         vnode.state.sessionDB = new window.models.SessionDB()
         vnode.state.searchEntered = m.stream('')
         vnode.state.searchStart = m.stream('')
         vnode.state.searchStart.map(function(q) {
-            var sessions = vnode.state.sessionDB.loadAll()
-            var cookie = (new Date()).getTime()
-            // Each time searchStart() is called we replace the
-            // vnode.state.results stream with a new one, and use
-            // the local variable to update results in callbacks. This
-            // avoids crosstalk between AJAX calls from consecutive
-            // searches.
-            var results = {
-                // Sorted items ready to display, merged from all
-                // pagers.
-                displayable: [],
-                pagers: {},
-                loadMore: false,
-                // Number of undisplayed items to keep on hand for
-                // each result set. When hitting "load more", if a
-                // result set already has this many additional results
-                // available, we don't bother fetching a new
-                // page. This is the _minimum_ number of rows that
-                // will be added to results.displayable in each "load
-                // more" event (except for the case where all items
-                // are displayed).
-                lowWaterMark: 23,
-            }
-            vnode.state.results = results
-            m.stream.merge(Object.keys(sessions).map(function(key) {
-                var pager = new Pager(function(filters) {
+            vnode.state.loader = new window.models.MultisiteLoader({
+                loadFunc: function(session, filters) {
                     if (q)
                         filters.push(['any', '@@', q+':*'])
-                    return vnode.state.sessionDB.request(sessions[key], 'arvados/v1/collections', {
+                    return vnode.state.sessionDB.request(session, 'arvados/v1/collections', {
                         data: {
                             filters: JSON.stringify(filters),
                             count: 'none',
                         },
                     })
-                })
-                results.pagers[key] = pager
-                pager.loadNextPage()
-                // Resolve the stream with the session key when the
-                // results arrive.
-                return pager.items.map(function() { return key })
-            })).map(function(keys) {
-                // Top (most recent) of {bottom (oldest) entry of any
-                // pager that still has more pages left to fetch}
-                var cutoff
-                keys.forEach(function(key) {
-                    var pager = results.pagers[key]
-                    var items = pager.items()
-                    if (items.length == 0 || pager.done)
-                        return
-                    var last = items[items.length-1].modified_at
-                    if (!cutoff || cutoff < last)
-                        cutoff = last
-                })
-                var combined = []
-                keys.forEach(function(key) {
-                    var pager = results.pagers[key]
-                    pager.itemsDisplayed = 0
-                    pager.items().every(function(item) {
-                        if (cutoff && item.modified_at < cutoff)
-                            // Some other pagers haven't caught up to
-                            // this point, so don't display this item
-                            // or anything after it.
-                            return false
-                        item.session = sessions[key]
-                        combined.push(item)
-                        pager.itemsDisplayed++
-                        return true // continue
-                    })
-                })
-                results.displayable = combined.sort(function(a, b) {
-                    return a.modified_at < b.modified_at ? 1 : -1
-                })
-                // Make a new loadMore function that hits the pagers
-                // (if necessary according to lowWaterMark)... or set
-                // results.loadMore to false if there is nothing left
-                // to fetch.
-                var loadable = []
-                Object.keys(results.pagers).map(function(key) {
-                    if (!results.pagers[key].done)
-                        loadable.push(results.pagers[key])
-                })
-                if (loadable.length == 0)
-                    results.loadMore = false
-                else
-                    results.loadMore = function() {
-                        results.loadMore = false
-                        loadable.map(function(pager) {
-                            if (pager.items().length - pager.itemsDisplayed < results.lowWaterMark)
-                                pager.loadNextPage()
-                        })
-                    }
+                },
+                sessionDB: vnode.state.sessionDB,
             })
         })
     },
@@ -195,15 +88,15 @@ window.components.collection_search = {
                         ? m('span.label.label-xs.label-danger', 'none')
                         : Object.keys(sessions).sort().map(function(key) {
                             return [m('span.label.label-xs', {
-                                className: vnode.state.results.pagers[key].items() ? 'label-info' : 'label-default',
+                                className: vnode.state.loader.pagers[key].items() ? 'label-info' : 'label-default',
                             }, key), ' ']
                         }),
                     ' ',
                     m('a[href="/sessions"]', 'Add/remove sites'),
                 ]),
             ]),
-            m(window.components.collection_table_narrow, {
-                results: vnode.state.results,
+            m(window.components.collection_table, {
+                loader: vnode.state.loader,
             }),
         ])
     },
diff --git a/apps/workbench/app/assets/javascripts/models/loader.js b/apps/workbench/app/assets/javascripts/models/loader.js
new file mode 100644
index 0000000..1dc7079
--- /dev/null
+++ b/apps/workbench/app/assets/javascripts/models/loader.js
@@ -0,0 +1,126 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+window.models = window.models || {}
+window.models.Pager = function(loadFunc) {
+    // loadFunc(filters) must return a promise for a page of results.
+    var pager = this
+    Object.assign(pager, {
+        done: false,
+        items: m.stream(),
+        thresholdItem: null,
+        loadNextPage: function() {
+            // Get the next page, if there are any more items to get.
+            if (pager.done)
+                return
+            var filters = pager.thresholdItem ? [
+                ["modified_at", "<=", pager.thresholdItem.modified_at],
+                ["uuid", "!=", pager.thresholdItem.uuid],
+            ] : []
+            loadFunc(filters).then(function(resp) {
+                var items = pager.items() || []
+                Array.prototype.push.apply(items, resp.items)
+                if (resp.items.length == 0)
+                    pager.done = true
+                else
+                    pager.thresholdItem = resp.items[resp.items.length-1]
+                pager.items(items)
+            })
+        },
+    })
+}
+
+// MultisiteLoader loads pages of results from multiple API sessions
+// and merges them into a single result set.
+//
+// The constructor implicitly starts an initial page load for each
+// session.
+//
+// new MultisiteLoader({loadFunc: function(session, filters){...},
+// sessionDB: new window.models.SessionDB()}
+//
+// At any given time, ml.loadMore will be either false (meaning a page
+// load is in progress or there are no more results to fetch) or a
+// function that starts loading more results.
+//
+// loadFunc() must retrieve results in "modified_at desc" order.
+window.models = window.models || {}
+window.models.MultisiteLoader = function(config) {
+    var loader = this
+    if (!(config.loadFunc && config.sessionDB))
+        throw new Error("MultisiteLoader constructor requires loadFunc and sessionDB")
+    Object.assign(loader, config, {
+        // Sorted items ready to display, merged from all pagers.
+        displayable: [],
+        pagers: {},
+        loadMore: false,
+        // Number of undisplayed items to keep on hand for each result
+        // set. When hitting "load more", if a result set already has
+        // this many additional results available, we don't bother
+        // fetching a new page. This is the _minimum_ number of rows
+        // that will be added to loader.displayable in each "load
+        // more" event (except for the case where all items are
+        // displayed).
+        lowWaterMark: 23,
+    })
+    var sessions = loader.sessionDB.loadAll()
+    m.stream.merge(Object.keys(sessions).map(function(key) {
+        var pager = new window.models.Pager(loader.loadFunc.bind(null, sessions[key]))
+        loader.pagers[key] = pager
+        pager.loadNextPage()
+        // Resolve the stream with the session key when the results
+        // arrive.
+        return pager.items.map(function() { return key })
+    })).map(function(keys) {
+        // Top (most recent) of {bottom (oldest) entry of any pager
+        // that still has more pages left to fetch}
+        var cutoff
+        keys.forEach(function(key) {
+            var pager = loader.pagers[key]
+            var items = pager.items()
+            if (items.length == 0 || pager.done)
+                return
+            var last = items[items.length-1].modified_at
+            if (!cutoff || cutoff < last)
+                cutoff = last
+        })
+        var combined = []
+        keys.forEach(function(key) {
+            var pager = loader.pagers[key]
+            pager.itemsDisplayed = 0
+            pager.items().every(function(item) {
+                if (cutoff && item.modified_at < cutoff)
+                    // Some other pagers haven't caught up to this
+                    // point, so don't display this item or anything
+                    // after it.
+                    return false
+                item.session = sessions[key]
+                combined.push(item)
+                pager.itemsDisplayed++
+                return true // continue
+            })
+        })
+        loader.displayable = combined.sort(function(a, b) {
+            return a.modified_at < b.modified_at ? 1 : -1
+        })
+        // Make a new loadMore function that hits the pagers (if
+        // necessary according to lowWaterMark)... or set
+        // loader.loadMore to false if there is nothing left to fetch.
+        var loadable = []
+        Object.keys(loader.pagers).map(function(key) {
+            if (!loader.pagers[key].done)
+                loadable.push(loader.pagers[key])
+        })
+        if (loadable.length == 0)
+            loader.loadMore = false
+        else
+            loader.loadMore = function() {
+                loader.loadMore = false
+                loadable.map(function(pager) {
+                    if (pager.items().length - pager.itemsDisplayed < loader.lowWaterMark)
+                        pager.loadNextPage()
+                })
+            }
+    })
+}

commit 2014757448a9ce52f2aa4f6af4ce2284c6858bb5
Author: Tom Clegg <tom at curoverse.com>
Date:   Thu Aug 10 13:48:31 2017 -0400

    12033: Add "load more" button.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at curoverse.com>

diff --git a/apps/workbench/app/assets/javascripts/components/collections.js b/apps/workbench/app/assets/javascripts/components/collections.js
index 0c821e9..9334bcc 100644
--- a/apps/workbench/app/assets/javascripts/components/collections.js
+++ b/apps/workbench/app/assets/javascripts/components/collections.js
@@ -13,7 +13,7 @@ window.components.collection_table_narrow = {
                 m('th', 'last modified'),
             ])),
             m('tbody', [
-                vnode.attrs.items.map(function(item) {
+                vnode.attrs.results.displayable.map(function(item) {
                     return m('tr', [
                         m('td', m('a.btn.btn-xs.btn-default', {href: item.session.baseURL.replace('://', '://workbench.')+'/collections/'+item.uuid}, 'Show')),
                         m('td', item.uuid),
@@ -22,6 +22,22 @@ window.components.collection_table_narrow = {
                     ])
                 }),
             ]),
+            m('tfoot', m('tr', [
+                m('th[colspan=4]', m('button.btn.btn-xs', {
+                    className: vnode.attrs.results.loadMore ? 'btn-primary' : 'btn-default',
+                    style: {
+                        display: 'block',
+                        width: '12em',
+                        marginLeft: 'auto',
+                        marginRight: 'auto',
+                    },
+                    disabled: !vnode.attrs.results.loadMore,
+                    onclick: function() {
+                        vnode.attrs.results.loadMore()
+                        return false
+                    },
+                }, vnode.attrs.results.loadMore ? 'Load more' : '(loading)')),
+            ])),
         ])
     },
 }
@@ -32,19 +48,22 @@ function Pager(loadFunc) {
     Object.assign(pager, {
         done: false,
         items: m.stream(),
-        lastModifiedAt: null,
+        thresholdItem: null,
         loadNextPage: function() {
             // Get the next page, if there are any more items to get.
             if (pager.done)
                 return
-            var filters = pager.lastModifiedAt ? [["modified_at", "<=", pager.lastModifiedAt]] : []
+            var filters = pager.thresholdItem ? [
+                ["modified_at", "<=", pager.thresholdItem.modified_at],
+                ["uuid", "!=", pager.thresholdItem.uuid],
+            ] : []
             loadFunc(filters).then(function(resp) {
                 var items = pager.items() || []
                 Array.prototype.push.apply(items, resp.items)
                 if (resp.items.length == 0)
                     pager.done = true
                 else
-                    pager.lastModifiedAt = resp.items[resp.items.length-1].modified_at
+                    pager.thresholdItem = resp.items[resp.items.length-1]
                 pager.items(items)
             })
         },
@@ -56,15 +75,31 @@ window.components.collection_search = {
         vnode.state.sessionDB = new window.models.SessionDB()
         vnode.state.searchEntered = m.stream('')
         vnode.state.searchStart = m.stream('')
-        // items ready to display
-        vnode.state.displayItems = m.stream([])
-        // {sessionKey -> Pager}
-        vnode.state.pagers = {}
         vnode.state.searchStart.map(function(q) {
             var sessions = vnode.state.sessionDB.loadAll()
             var cookie = (new Date()).getTime()
-            var displayItems = m.stream([])
-            vnode.state.displayItems = displayItems
+            // Each time searchStart() is called we replace the
+            // vnode.state.results stream with a new one, and use
+            // the local variable to update results in callbacks. This
+            // avoids crosstalk between AJAX calls from consecutive
+            // searches.
+            var results = {
+                // Sorted items ready to display, merged from all
+                // pagers.
+                displayable: [],
+                pagers: {},
+                loadMore: false,
+                // Number of undisplayed items to keep on hand for
+                // each result set. When hitting "load more", if a
+                // result set already has this many additional results
+                // available, we don't bother fetching a new
+                // page. This is the _minimum_ number of rows that
+                // will be added to results.displayable in each "load
+                // more" event (except for the case where all items
+                // are displayed).
+                lowWaterMark: 23,
+            }
+            vnode.state.results = results
             m.stream.merge(Object.keys(sessions).map(function(key) {
                 var pager = new Pager(function(filters) {
                     if (q)
@@ -76,20 +111,62 @@ window.components.collection_search = {
                         },
                     })
                 })
-                vnode.state.pagers[key] = pager
+                results.pagers[key] = pager
                 pager.loadNextPage()
+                // Resolve the stream with the session key when the
+                // results arrive.
                 return pager.items.map(function() { return key })
             })).map(function(keys) {
+                // Top (most recent) of {bottom (oldest) entry of any
+                // pager that still has more pages left to fetch}
+                var cutoff
+                keys.forEach(function(key) {
+                    var pager = results.pagers[key]
+                    var items = pager.items()
+                    if (items.length == 0 || pager.done)
+                        return
+                    var last = items[items.length-1].modified_at
+                    if (!cutoff || cutoff < last)
+                        cutoff = last
+                })
                 var combined = []
                 keys.forEach(function(key) {
-                    vnode.state.pagers[key].items().forEach(function(item) {
+                    var pager = results.pagers[key]
+                    pager.itemsDisplayed = 0
+                    pager.items().every(function(item) {
+                        if (cutoff && item.modified_at < cutoff)
+                            // Some other pagers haven't caught up to
+                            // this point, so don't display this item
+                            // or anything after it.
+                            return false
                         item.session = sessions[key]
                         combined.push(item)
+                        pager.itemsDisplayed++
+                        return true // continue
                     })
                 })
-                displayItems(combined.sort(function(a, b) {
+                results.displayable = combined.sort(function(a, b) {
                     return a.modified_at < b.modified_at ? 1 : -1
-                }))
+                })
+                // Make a new loadMore function that hits the pagers
+                // (if necessary according to lowWaterMark)... or set
+                // results.loadMore to false if there is nothing left
+                // to fetch.
+                var loadable = []
+                Object.keys(results.pagers).map(function(key) {
+                    if (!results.pagers[key].done)
+                        loadable.push(results.pagers[key])
+                })
+                if (loadable.length == 0)
+                    results.loadMore = false
+                else
+                    results.loadMore = function() {
+                        results.loadMore = false
+                        loadable.map(function(pager) {
+                            if (pager.items().length - pager.itemsDisplayed < results.lowWaterMark)
+                                pager.loadNextPage()
+                        })
+                    }
             })
         })
     },
@@ -118,7 +195,7 @@ window.components.collection_search = {
                         ? m('span.label.label-xs.label-danger', 'none')
                         : Object.keys(sessions).sort().map(function(key) {
                             return [m('span.label.label-xs', {
-                                className: vnode.state.pagers[key].items() ? 'label-info' : 'label-default',
+                                className: vnode.state.results.pagers[key].items() ? 'label-info' : 'label-default',
                             }, key), ' ']
                         }),
                     ' ',
@@ -126,7 +203,7 @@ window.components.collection_search = {
                 ]),
             ]),
             m(window.components.collection_table_narrow, {
-                items: vnode.state.displayItems(),
+                results: vnode.state.results,
             }),
         ])
     },

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list