12033: Load more results automatically on scroll.
[arvados.git] / apps / workbench / app / assets / javascripts / components / collections.js
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 window.components = window.components || {}
6 window.components.collection_table = {
7     oncreate: function(vnode) {
8         vnode.state.autoload = function() {
9             if (!vnode.attrs.loader.loadMore)
10                 // Can't load more content anyway: no point in
11                 // checking anything else.
12                 return
13             var contentRect = vnode.dom.getBoundingClientRect()
14             var scroller = window // TODO: use vnode.dom's nearest ancestor with scrollbars
15             if (contentRect.bottom < 2 * scroller.innerHeight) {
16                 // We have less than 1 page worth of content available
17                 // below the visible area. Load more.
18                 vnode.attrs.loader.loadMore()
19                 // Indicate loading is in progress.
20                 window.requestAnimationFrame(m.redraw)
21             }
22         }
23         window.addEventListener('scroll', vnode.state.autoload)
24         window.addEventListener('resize', vnode.state.autoload)
25         vnode.state.autoloadTimer = window.setInterval(vnode.state.autoload, 200)
26     },
27     onremove: function(vnode) {
28         window.clearInterval(vnode.state.autoloadTimer)
29         window.removeEventListener('scroll', vnode.state.autoload)
30         window.removeEventListener('resize', vnode.state.autoload)
31     },
32     view: function(vnode) {
33         return m('table.table.table-condensed', [
34             m('thead', m('tr', [
35                 m('th'),
36                 m('th', 'uuid'),
37                 m('th', 'name'),
38                 m('th', 'last modified'),
39             ])),
40             m('tbody', [
41                 vnode.attrs.loader.displayable.map(function(item) {
42                     return m('tr', [
43                         m('td', m('a.btn.btn-xs.btn-default', {href: item.session.baseURL.replace('://', '://workbench.')+'/collections/'+item.uuid}, 'Show')),
44                         m('td.arvados-uuid', item.uuid),
45                         m('td', item.name || '(unnamed)'),
46                         m('td', m(window.components.datetime, {parse: item.modified_at})),
47                     ])
48                 }),
49             ]),
50             m('tfoot', m('tr', [
51                 m('th[colspan=4]', m('button.btn.btn-xs', {
52                     className: vnode.attrs.loader.loadMore ? 'btn-primary' : 'btn-default',
53                     style: {
54                         display: 'block',
55                         width: '12em',
56                         marginLeft: 'auto',
57                         marginRight: 'auto',
58                     },
59                     disabled: !vnode.attrs.loader.loadMore,
60                     onclick: function() {
61                         vnode.attrs.loader.loadMore()
62                         return false
63                     },
64                 }, vnode.attrs.loader.loadMore ? 'Load more' : '(loading)')),
65             ])),
66         ])
67     },
68 }
69
70 window.components.collection_search = {
71     oninit: function(vnode) {
72         vnode.state.sessionDB = new window.models.SessionDB()
73         vnode.state.searchEntered = m.stream('')
74         vnode.state.searchStart = m.stream('')
75         vnode.state.searchStart.map(function(q) {
76             vnode.state.loader = new window.models.MultisiteLoader({
77                 loadFunc: function(session, filters) {
78                     if (q)
79                         filters.push(['any', '@@', q+':*'])
80                     return vnode.state.sessionDB.request(session, 'arvados/v1/collections', {
81                         data: {
82                             filters: JSON.stringify(filters),
83                             count: 'none',
84                         },
85                     })
86                 },
87                 sessionDB: vnode.state.sessionDB,
88             })
89         })
90     },
91     view: function(vnode) {
92         var sessions = vnode.state.sessionDB.loadAll()
93         return m('form', {
94             onsubmit: function() {
95                 vnode.state.searchStart(vnode.state.searchEntered())
96                 return false
97             },
98         }, [
99             m('.row', [
100                 m('.col-md-6', [
101                     m('.input-group', [
102                         m('input#search.form-control[placeholder=Search]', {
103                             oninput: m.withAttr('value', vnode.state.searchEntered),
104                         }),
105                         m('.input-group-btn', [
106                             m('input.btn.btn-primary[type=submit][value="Search"]'),
107                         ]),
108                     ]),
109                 ]),
110                 m('.col-md-6', [
111                     'Searching sites: ',
112                     Object.keys(sessions).length == 0
113                         ? m('span.label.label-xs.label-danger', 'none')
114                         : Object.keys(sessions).sort().map(function(key) {
115                             return [m('span.label.label-xs', {
116                                 className: vnode.state.loader.pagers[key].items() ? 'label-info' : 'label-default',
117                             }, key), ' ']
118                         }),
119                     ' ',
120                     m('a[href="/sessions"]', 'Add/remove sites'),
121                 ]),
122             ]),
123             m(window.components.collection_table, {
124                 loader: vnode.state.loader,
125             }),
126         ])
127     },
128 }