More view refactor I guess
This commit is contained in:
parent
53725e72bb
commit
753cf16e9d
5 changed files with 166 additions and 56 deletions
|
|
@ -589,6 +589,13 @@ def sort_key(f: Feed) -> int:
|
|||
return -1
|
||||
|
||||
|
||||
def sort_key_inserted(f: Feed) -> int:
|
||||
"""A sort key for sorting feeds by recency."""
|
||||
if len(f.entries) > 0:
|
||||
return max(e.inserted_at for e in f.entries)
|
||||
return -1
|
||||
|
||||
|
||||
class FeedSearchParser(html.parser.HTMLParser):
|
||||
"""An HTML parser that tries to find links to feeds."""
|
||||
|
||||
|
|
|
|||
65
cry/static/event.js
Normal file
65
cry/static/event.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
function append_log(txt) {
|
||||
log = document.getElementById("log");
|
||||
log.append(txt + "\n");
|
||||
log.scrollTop = log.scrollHeight;
|
||||
}
|
||||
|
||||
var events = new EventSource(window.location.pathname + "/events");
|
||||
events.addEventListener("status", (e) => {
|
||||
console.log(e);
|
||||
append_log(e.data);
|
||||
document.getElementById("status").innerText = e.data;
|
||||
});
|
||||
|
||||
events.addEventListener("log", (e) => {
|
||||
console.log(e);
|
||||
append_log(e.data);
|
||||
});
|
||||
|
||||
events.addEventListener("redirect", (e) => {
|
||||
console.log(e);
|
||||
window.location = e.data;
|
||||
});
|
||||
|
||||
events.addEventListener("progress", (e) => {
|
||||
// Grab the progress element being referred to.
|
||||
const parameters = JSON.parse(e.data);
|
||||
const progress = document.getElementById(parameters.progressElement);
|
||||
if (progress) {
|
||||
progress.value = parameters.progressValue;
|
||||
}
|
||||
|
||||
// Gather all the progress items into an array.
|
||||
const progressBarElements = [...document.querySelectorAll('.progress-entry')];
|
||||
|
||||
// Sort the array by the progress value, but put completed items at the end.
|
||||
// If both items are completed sort by data-sort-key.
|
||||
progressBarElements.sort((a, b) => {
|
||||
const valueA = parseInt(a.querySelector('.progress').getAttribute('value'), 10);
|
||||
const maxA = parseInt(a.querySelector('.progress').getAttribute('max'), 10);
|
||||
const keyA = a.getAttribute('data-sort-key')
|
||||
|
||||
const valueB = parseInt(b.querySelector('.progress').getAttribute('value'), 10);
|
||||
const maxB = parseInt(b.querySelector('.progress').getAttribute('max'), 10);
|
||||
const keyB = b.getAttribute('data-sort-key')
|
||||
|
||||
if (valueA == maxA) {
|
||||
if (valueB == maxB) {
|
||||
return keyA.localeCompare(keyB);
|
||||
} else {
|
||||
return 1; // B is not at max, it goes first.
|
||||
}
|
||||
} else if (valueB == maxB) {
|
||||
return -1; // A is not at max, it goes first.
|
||||
} else {
|
||||
return valueB - valueA; // Larger values first.
|
||||
}
|
||||
|
||||
return valueA - valueB; // Sort in ascending order (lowest to highest value)
|
||||
});
|
||||
|
||||
const parentContainer = progressBarElements[0].parentNode;
|
||||
progressBarElements.forEach(element => {
|
||||
parentContainer.appendChild(element);
|
||||
});
|
||||
})
|
||||
|
|
@ -7,20 +7,12 @@ body {
|
|||
height: 100vh;
|
||||
}
|
||||
|
||||
header {
|
||||
/* padding: 10px; */
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1; /* This makes the content section fill the available space */
|
||||
overflow-y: auto; /* Allows vertical scrolling */
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 0.25rem;
|
||||
|
|
@ -134,3 +126,27 @@ li.entry:before {
|
|||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
* STATUS
|
||||
*/
|
||||
.status-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.status-header {
|
||||
|
||||
}
|
||||
|
||||
.status-log {
|
||||
flex-grow: 1;
|
||||
overflow-y: scroll;
|
||||
padding: 10px;
|
||||
max-height: 100%;
|
||||
margin: auto 0 auto 0;
|
||||
}
|
||||
|
||||
.status-footer {
|
||||
|
||||
}
|
||||
|
|
|
|||
60
cry/views.py
60
cry/views.py
|
|
@ -164,3 +164,63 @@ def subscribe_choose_view(candidates: typing.Iterable[tuple[str, str]]) -> tags.
|
|||
)
|
||||
assert isinstance(document, tags.html)
|
||||
return document
|
||||
|
||||
|
||||
def status_view() -> tags.html:
|
||||
document = tags.html(
|
||||
_standard_header("Status"),
|
||||
tags.body(
|
||||
{"class": "status-body"},
|
||||
tags.header(
|
||||
{"class": "status-header"},
|
||||
tags.h1("Status"),
|
||||
tags.h2("Status: ", tags.span({"id": "status"}, "Starting...")),
|
||||
),
|
||||
tags.pre({"class": "status-log", "id": "log"}),
|
||||
tags.footer(
|
||||
{"class": "status-footer"},
|
||||
tags.a({"href": "/"}, "Back to feeds"),
|
||||
),
|
||||
tags.script({"src": "/event.js"}),
|
||||
),
|
||||
)
|
||||
assert isinstance(document, tags.html)
|
||||
return document
|
||||
|
||||
|
||||
def refresh_view(feeds: list[feed.Feed]) -> tags.html:
|
||||
document = tags.html(
|
||||
_standard_header("Refreshing Feeds..."),
|
||||
tags.body(
|
||||
{"class": "refresh-body"},
|
||||
tags.header(
|
||||
{"class": "refresh-header"},
|
||||
tags.h1("Status"),
|
||||
tags.h2("Status: ", tags.span({"id": "status"}, "Starting...")),
|
||||
),
|
||||
tags.div(
|
||||
{"class": "refresh-content"},
|
||||
(
|
||||
tags.div(
|
||||
{"class": "progress-entry", "data-sort-key": f.title},
|
||||
tags.label(
|
||||
{"class": "progress-label"},
|
||||
f.title,
|
||||
tags.progress(
|
||||
{"max": 100, "value": 0, "class": "progress"}
|
||||
),
|
||||
),
|
||||
)
|
||||
for f in feeds
|
||||
),
|
||||
),
|
||||
tags.pre({"class": "refresh-log", "id": "log"}),
|
||||
tags.footer(
|
||||
{"class": "status-footer"},
|
||||
tags.a({"href": "/"}, "Back to feeds"),
|
||||
),
|
||||
tags.script({"src": "/event.js"}),
|
||||
),
|
||||
)
|
||||
assert isinstance(document, tags.html)
|
||||
return document
|
||||
|
|
|
|||
58
cry/web.py
58
cry/web.py
|
|
@ -339,6 +339,8 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||
return self.serve_feeds()
|
||||
elif self.path == "/style.css":
|
||||
return self.serve_style()
|
||||
elif self.path == "/event.js":
|
||||
return self.serve_event_js()
|
||||
elif self.path == "/refresh-status":
|
||||
return self.serve_status()
|
||||
elif self.path == "/subscribe-status":
|
||||
|
|
@ -439,55 +441,9 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||
self.wfile.flush()
|
||||
|
||||
def serve_status(self):
|
||||
# TODO: FIX STYLES TO BE INLINE FOR SPEED I GUESS
|
||||
buffer = io.StringIO()
|
||||
buffer.write(
|
||||
"""
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Status</title>
|
||||
<link rel="stylesheet" href="/style.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Status</h1>
|
||||
<h2>Status: <span id="status">Starting...</span></h2>
|
||||
</header>
|
||||
document = views.status_view()
|
||||
|
||||
<pre class="content" id="log"></pre>
|
||||
|
||||
<footer>
|
||||
<a href="/">Back to feeds</a>
|
||||
</footer>
|
||||
</div>
|
||||
<script>
|
||||
function append_log(txt) {
|
||||
log = document.getElementById("log");
|
||||
log.append(txt + "\\n");
|
||||
log.scrollTop = log.scrollHeight;
|
||||
}
|
||||
var events = new EventSource(window.location.pathname + "/events");
|
||||
events.addEventListener("status", (e) => {
|
||||
console.log(e);
|
||||
append_log(e.data);
|
||||
document.getElementById("status").innerText = e.data;
|
||||
});
|
||||
events.addEventListener("log", (e) => {
|
||||
console.log(e);
|
||||
append_log(e.data);
|
||||
});
|
||||
events.addEventListener("redirect", (e) => {
|
||||
console.log(e);
|
||||
window.location = e.data;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
"""
|
||||
)
|
||||
|
||||
self.write_html(buffer.getvalue())
|
||||
self.write_html("<!DOCTYPE html>\n" + document.render())
|
||||
|
||||
def serve_feeds(self):
|
||||
db = database.Database.local()
|
||||
|
|
@ -522,6 +478,12 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||
self.end_headers()
|
||||
self.wfile.write(response)
|
||||
|
||||
def serve_event_js(self):
|
||||
self.write_file(
|
||||
pathlib.Path(__file__).parent / "static" / "event.js",
|
||||
content_type="text/javascript",
|
||||
)
|
||||
|
||||
def serve_style(self):
|
||||
self.write_file(
|
||||
pathlib.Path(__file__).parent / "static" / "style.css",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue