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
-
-
+
refresh
+
control-panel
+ Filter:
+
size |
who |
@@ -29,27 +26,12 @@
age |
dir |
file |
-
- {% for vp, evp, sz, ip, at in rows %}
-
-{{ sz }} |
-{{ ip }} |
-{{ at }} |
-{{ (now-at) }} |
- |
-{{ vp|e }} |
-
- {% endfor %}
-
- {% 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"