1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 window.components = window.components || {}
6 window.components.collection_table_narrow = {
7 view: function(vnode) {
8 return m('table.table.table-condensed', [
13 m('th', 'last modified'),
16 vnode.attrs.results.displayable.map(function(item) {
18 m('td', m('a.btn.btn-xs.btn-default', {href: item.session.baseURL.replace('://', '://workbench.')+'/collections/'+item.uuid}, 'Show')),
20 m('td', item.name || '(unnamed)'),
21 m('td', m(window.components.datetime, {parse: item.modified_at})),
26 m('th[colspan=4]', m('button.btn.btn-xs', {
27 className: vnode.attrs.results.loadMore ? 'btn-primary' : 'btn-default',
34 disabled: !vnode.attrs.results.loadMore,
36 vnode.attrs.results.loadMore()
39 }, vnode.attrs.results.loadMore ? 'Load more' : '(loading)')),
45 function Pager(loadFunc) {
46 // loadFunc(filters) returns a promise for a page of results.
48 Object.assign(pager, {
52 loadNextPage: function() {
53 // Get the next page, if there are any more items to get.
56 var filters = pager.thresholdItem ? [
57 ["modified_at", "<=", pager.thresholdItem.modified_at],
58 ["uuid", "!=", pager.thresholdItem.uuid],
60 loadFunc(filters).then(function(resp) {
61 var items = pager.items() || []
62 Array.prototype.push.apply(items, resp.items)
63 if (resp.items.length == 0)
66 pager.thresholdItem = resp.items[resp.items.length-1]
73 window.components.collection_search = {
74 oninit: function(vnode) {
75 vnode.state.sessionDB = new window.models.SessionDB()
76 vnode.state.searchEntered = m.stream('')
77 vnode.state.searchStart = m.stream('')
78 vnode.state.searchStart.map(function(q) {
79 var sessions = vnode.state.sessionDB.loadAll()
80 var cookie = (new Date()).getTime()
81 // Each time searchStart() is called we replace the
82 // vnode.state.results stream with a new one, and use
83 // the local variable to update results in callbacks. This
84 // avoids crosstalk between AJAX calls from consecutive
87 // Sorted items ready to display, merged from all
92 // Number of undisplayed items to keep on hand for
93 // each result set. When hitting "load more", if a
94 // result set already has this many additional results
95 // available, we don't bother fetching a new
96 // page. This is the _minimum_ number of rows that
97 // will be added to results.displayable in each "load
98 // more" event (except for the case where all items
102 vnode.state.results = results
103 m.stream.merge(Object.keys(sessions).map(function(key) {
104 var pager = new Pager(function(filters) {
106 filters.push(['any', '@@', q+':*'])
107 return vnode.state.sessionDB.request(sessions[key], 'arvados/v1/collections', {
109 filters: JSON.stringify(filters),
114 results.pagers[key] = pager
116 // Resolve the stream with the session key when the
118 return pager.items.map(function() { return key })
119 })).map(function(keys) {
120 // Top (most recent) of {bottom (oldest) entry of any
121 // pager that still has more pages left to fetch}
123 keys.forEach(function(key) {
124 var pager = results.pagers[key]
125 var items = pager.items()
126 if (items.length == 0 || pager.done)
128 var last = items[items.length-1].modified_at
129 if (!cutoff || cutoff < last)
133 keys.forEach(function(key) {
134 var pager = results.pagers[key]
135 pager.itemsDisplayed = 0
136 pager.items().every(function(item) {
137 if (cutoff && item.modified_at < cutoff)
138 // Some other pagers haven't caught up to
139 // this point, so don't display this item
140 // or anything after it.
142 item.session = sessions[key]
144 pager.itemsDisplayed++
145 return true // continue
148 results.displayable = combined.sort(function(a, b) {
149 return a.modified_at < b.modified_at ? 1 : -1
151 // Make a new loadMore function that hits the pagers
152 // (if necessary according to lowWaterMark)... or set
153 // results.loadMore to false if there is nothing left
156 Object.keys(results.pagers).map(function(key) {
157 if (!results.pagers[key].done)
158 loadable.push(results.pagers[key])
160 if (loadable.length == 0)
161 results.loadMore = false
163 results.loadMore = function() {
164 results.loadMore = false
165 loadable.map(function(pager) {
166 if (pager.items().length - pager.itemsDisplayed < results.lowWaterMark)
173 view: function(vnode) {
174 var sessions = vnode.state.sessionDB.loadAll()
176 onsubmit: function() {
177 vnode.state.searchStart(vnode.state.searchEntered())
184 m('input#search.form-control[placeholder=Search]', {
185 oninput: m.withAttr('value', vnode.state.searchEntered),
187 m('.input-group-btn', [
188 m('input.btn.btn-primary[type=submit][value="Search"]'),
194 Object.keys(sessions).length == 0
195 ? m('span.label.label-xs.label-danger', 'none')
196 : Object.keys(sessions).sort().map(function(key) {
197 return [m('span.label.label-xs', {
198 className: vnode.state.results.pagers[key].items() ? 'label-info' : 'label-default',
202 m('a[href="/sessions"]', 'Add/remove sites'),
205 m(window.components.collection_table_narrow, {
206 results: vnode.state.results,