diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 294a8f67..439117e4 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -5031,11 +5031,11 @@ class HttpCli(object): ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore ret = ret[:2000] + ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore + if len(ret) > 2000: ret = ret[:2000] - ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore - for rv in ret: rv["vp"] = quotep(rv["vp"]) nfk = rv.pop("nfk") @@ -5124,10 +5124,6 @@ class HttpCli(object): if not dots and "/." in vp: continue - n -= 1 - if not n: - break - rv = { "vp": vp, "sz": sz, @@ -5145,13 +5141,17 @@ class HttpCli(object): ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore ret = ret[:1000] - if len(ret) > 1000: - ret = ret[:1000] + n -= 1 + if not n: + break ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore + if len(ret) > 1000: + ret = ret[:1000] + for rv in ret: - rv["evp"] = quotep(rv["vp"]) + rv["vp"] = quotep(rv["vp"]) nfk = rv.pop("nfk") if not nfk: continue @@ -5184,15 +5184,16 @@ class HttpCli(object): for v in ret: v["vp"] = self.args.SR + v["vp"] - self.log("%s #%d %.2fsec" % (lm, len(ret), time.time() - t0)) + now = time.time() + self.log("%s #%d %.2fsec" % (lm, len(ret), now - t0)) + ret2 = {"now": int(now), "filter": sfilt, "ups": ret} + jtxt = json.dumps(ret2, separators=(",\n", ": ")) if "j" in self.ouparam: - jtxt = json.dumps(ret, separators=(",\n", ": ")) self.reply(jtxt.encode("utf-8", "replace"), mime="application/json") return True - rows = [[x["vp"], x["evp"], x["sz"], x["ip"], x["at"]] for x in ret] - html = self.j2s("rups", this=self, rows=rows, filt=sfilt, now=int(time.time())) + html = self.j2s("rups", this=self, v=jtxt) self.reply(html.encode("utf-8"), status=200) return True diff --git a/copyparty/web/rups.css b/copyparty/web/rups.css index b5885999..7b8de38b 100644 --- a/copyparty/web/rups.css +++ b/copyparty/web/rups.css @@ -10,16 +10,10 @@ html { padding: 0 1em 3em 1em; line-height: 2.3em; } -form { - display: inline; - padding-left: 1em; -} -input[type=submit], a { color: #047; background: #fff; text-decoration: none; - border: none; border-bottom: 1px solid #8ab; border-radius: .2em; padding: .2em .6em; @@ -89,7 +83,6 @@ html.bz { background: #11121d; color: #bbd; } -html.z input[type=submit], html.z a { color: #fff; background: #057; diff --git a/copyparty/web/rups.html b/copyparty/web/rups.html index 63770359..5d286cae 100644 --- a/copyparty/web/rups.html +++ b/copyparty/web/rups.html @@ -6,6 +6,7 @@ {{ s_doctitle }} + @@ -14,14 +15,10 @@
- refresh - control-panel -
- - Filter: - -
- + refresh + control-panel +   Filter: +   @@ -29,27 +26,12 @@ - - {% for vp, evp, sz, ip, at in rows %} - - - - - - - - - {% endfor %} -
size whoage dir file
{{ sz }}{{ ip }}{{ at }}{{ (now-at) }}{{ vp|e }}
- {% if not rows %} - (the database is not aware of any uploads) - {% endif %} +
π + {%- if js %} diff --git a/copyparty/web/rups.js b/copyparty/web/rups.js index f4af40ee..e476f0fe 100644 --- a/copyparty/web/rups.js +++ b/copyparty/web/rups.js @@ -1,34 +1,66 @@ -(function() { - var tab = ebi('tab').tBodies[0], - tr = Array.prototype.slice.call(tab.rows, 0), - rows = []; +function render() { + var ups = V.ups, now = V.now, html = []; + ebi('filter').value = V.filter; + ebi('hits').innerHTML = 'showing ' + ups.length + ' files'; - for (var a = 0; a < tr.length; a++) { - var td = tr[a].cells, - an = td[5].children[0]; + for (var a = 0; a < ups.length; a++) { + var f = ups[a], + vsp = vsplit(f.vp.split('?')[0]), + dn = esc(uricom_dec(vsp[0])), + fn = esc(uricom_dec(vsp[1])), + at = f.at, + td = now - f.at, + ts = !at ? '(?)' : unix2iso(at), + sa = !at ? '(?)' : td > 60 ? shumantime(td) : (td + 's'), + sz = ('' + f.sz).replace(/\B(?=(\d{3})+(?!\d))/g, " "); - rows.push([ - td[0].textContent, - td[2].textContent, - td[3].textContent, - an.textContent, - an.getAttribute('href'), - ]); + html.push('' + sz + + '' + f.ip + + '' + ts + + '' + sa + + '' + dn + + '' + fn + + ''); } - - for (var a = 0; a < rows.length; a++) { - var t = rows[a], - sz = t[0], - at = parseInt(t[1]), - nam = vsplit(t[3]), - dh = vsplit(t[4])[0]; - - tr[a].cells[0].innerHTML = sz.replace(/\B(?=(\d{3})+(?!\d))/g, " "); - tr[a].cells[2].innerHTML = at ? unix2iso(at) : '(?)'; - tr[a].cells[3].innerHTML = at ? shumantime(t[2]) : '(?)'; - tr[a].cells[4].innerHTML = '' + nam[0] + ''; - tr[a].cells[5].children[0].innerHTML = nam[1].split('?')[0]; + if (!ups.length) { + var t = V.filter ? ' matching the filter' : ''; + html = ['there are no uploads' + t + '']; } + ebi('tb').innerHTML = html.join(''); +} +render(); - ebi('hits').innerHTML = '-- showing ' + rows.length + ' files'; -})(); +var ti; +function ask(e) { + ev(e); + clearTimeout(ti); + ebi('hits').innerHTML = 'Loading...'; + + var xhr = new XHR(), + filter = unsmart(ebi('filter').value); + + hist_replace(get_evpath().split('?')[0] + '?ru&filter=' + uricom_enc(filter)); + + xhr.onload = xhr.onerror = function () { + try { + V = JSON.parse(this.responseText) + } + catch (ex) { + ebi('tb').innerHTML = 'failed to decode server response as json:
' + esc(this.responseText) + '
'; + return; + } + render(); + }; + xhr.open('GET', SR + '/?ru&j&filter=' + uricom_enc(filter), true); + xhr.send(); +} +ebi('re').onclick = ask; +ebi('filter').oninput = function () { + clearTimeout(ti); + ti = setTimeout(ask, 500); + ebi('hits').innerHTML = '...'; +}; +ebi('filter').onkeydown = function (e) { + if (('' + e.key).endsWith('Enter')) + ask(); +}; diff --git a/copyparty/web/shares.html b/copyparty/web/shares.html index d1304e63..9c7dcd27 100644 --- a/copyparty/web/shares.html +++ b/copyparty/web/shares.html @@ -6,6 +6,7 @@ {{ s_doctitle }} + @@ -14,8 +15,8 @@
- refresh - control-panel + refresh + control-panel axs = perms (read,write,move,delet) nf = numFiles (0=dir) diff --git a/tests/util.py b/tests/util.py index e9369093..4d5d6556 100644 --- a/tests/util.py +++ b/tests/util.py @@ -275,8 +275,6 @@ class VHttpSrv(object): self.gurl = Garda("") self.u2idx = None - self.ptn_cc = re.compile(r"[\x00-\x1f]") - self.uparam_cc_ok = set("doc move tree".split()) def cachebuster(self): return "a"