Add sorting and filtering options to key ratings in index view
This commit is contained in:
102
app.py
102
app.py
@@ -20,6 +20,8 @@ def index():
|
|||||||
ORDER BY name
|
ORDER BY name
|
||||||
""").fetchall()
|
""").fetchall()
|
||||||
map_filter = request.args.get("map_id", type=int)
|
map_filter = request.args.get("map_id", type=int)
|
||||||
|
sort = request.args.get("sort", "priority_desc")
|
||||||
|
show = request.args.get("show", "all")
|
||||||
key_map_rows = conn.execute("""
|
key_map_rows = conn.execute("""
|
||||||
SELECT key_id, map_id
|
SELECT key_id, map_id
|
||||||
FROM key_maps
|
FROM key_maps
|
||||||
@@ -50,11 +52,24 @@ def index():
|
|||||||
params.append(map_filter)
|
params.append(map_filter)
|
||||||
key_query += """
|
key_query += """
|
||||||
LEFT JOIN key_ratings r ON k.id = r.key_id
|
LEFT JOIN key_ratings r ON k.id = r.key_id
|
||||||
ORDER BY
|
|
||||||
CASE WHEN r.priority IS NULL THEN 1 ELSE 0 END,
|
|
||||||
r.priority DESC,
|
|
||||||
k.name
|
|
||||||
"""
|
"""
|
||||||
|
if show == "rated":
|
||||||
|
key_query += " WHERE r.priority IS NOT NULL "
|
||||||
|
elif show == "unrated":
|
||||||
|
key_query += " WHERE r.priority IS NULL "
|
||||||
|
elif show == "quest":
|
||||||
|
key_query += " WHERE COALESCE(r.used_in_quest, 0) = 1 "
|
||||||
|
|
||||||
|
if sort == "name_asc":
|
||||||
|
order_by = "k.name ASC"
|
||||||
|
elif sort == "name_desc":
|
||||||
|
order_by = "k.name DESC"
|
||||||
|
elif sort == "priority_asc":
|
||||||
|
order_by = "CASE WHEN r.priority IS NULL THEN 1 ELSE 0 END, r.priority ASC, k.name"
|
||||||
|
else:
|
||||||
|
order_by = "CASE WHEN r.priority IS NULL THEN 1 ELSE 0 END, r.priority DESC, k.name"
|
||||||
|
|
||||||
|
key_query += f" ORDER BY {order_by} "
|
||||||
keys = conn.execute(key_query, params).fetchall()
|
keys = conn.execute(key_query, params).fetchall()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@@ -65,16 +80,22 @@ def index():
|
|||||||
maps=maps,
|
maps=maps,
|
||||||
key_maps=key_maps,
|
key_maps=key_maps,
|
||||||
map_filter=map_filter,
|
map_filter=map_filter,
|
||||||
|
sort=sort,
|
||||||
|
show=show,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/rate", methods=["POST"])
|
@app.route("/rate", methods=["POST"])
|
||||||
def rate_key():
|
def rate_key():
|
||||||
key_id = request.form["key_id"]
|
key_id = request.form["key_id"]
|
||||||
priority = request.form["priority"]
|
priority = request.form.get("priority")
|
||||||
|
if priority == "":
|
||||||
|
priority = None
|
||||||
reason = request.form.get("reason", "")
|
reason = request.form.get("reason", "")
|
||||||
used_in_quest = 1 if request.form.get("used_in_quest") == "on" else 0
|
used_in_quest = 1 if request.form.get("used_in_quest") == "on" else 0
|
||||||
map_filter = request.form.get("map_id")
|
map_filter = request.form.get("map_id")
|
||||||
|
sort = request.form.get("sort")
|
||||||
|
show = request.form.get("show")
|
||||||
map_ids = []
|
map_ids = []
|
||||||
for value in request.form.getlist("map_ids"):
|
for value in request.form.getlist("map_ids"):
|
||||||
try:
|
try:
|
||||||
@@ -101,9 +122,76 @@ def rate_key():
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
redirect_args = {}
|
||||||
if map_filter:
|
if map_filter:
|
||||||
return redirect(url_for("index", map_id=map_filter))
|
redirect_args["map_id"] = map_filter
|
||||||
return redirect(url_for("index"))
|
if sort:
|
||||||
|
redirect_args["sort"] = sort
|
||||||
|
if show:
|
||||||
|
redirect_args["show"] = show
|
||||||
|
base_url = url_for("index", **redirect_args)
|
||||||
|
return redirect(f"{base_url}#key-{key_id}")
|
||||||
|
|
||||||
|
|
||||||
|
def _update_key(conn, key_id, priority, reason, used_in_quest, map_ids):
|
||||||
|
conn.execute("""
|
||||||
|
INSERT INTO key_ratings (key_id, priority, reason, used_in_quest)
|
||||||
|
VALUES (?, ?, ?, ?)
|
||||||
|
ON CONFLICT(key_id) DO UPDATE SET
|
||||||
|
priority = excluded.priority,
|
||||||
|
reason = excluded.reason,
|
||||||
|
used_in_quest = excluded.used_in_quest,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
""", (key_id, priority, reason, used_in_quest))
|
||||||
|
conn.execute("DELETE FROM key_maps WHERE key_id = ?", (key_id,))
|
||||||
|
if map_ids:
|
||||||
|
conn.executemany(
|
||||||
|
"INSERT OR IGNORE INTO key_maps (key_id, map_id) VALUES (?, ?)",
|
||||||
|
[(key_id, map_id) for map_id in map_ids],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/rate_all", methods=["POST"])
|
||||||
|
def rate_all():
|
||||||
|
key_ids = request.form.getlist("key_ids")
|
||||||
|
save_one = request.form.get("save_one")
|
||||||
|
map_filter = request.form.get("map_id")
|
||||||
|
sort = request.form.get("sort")
|
||||||
|
show = request.form.get("show")
|
||||||
|
|
||||||
|
if save_one:
|
||||||
|
key_ids = [save_one]
|
||||||
|
|
||||||
|
conn = get_db()
|
||||||
|
for key_id in key_ids:
|
||||||
|
priority = request.form.get(f"priority_{key_id}")
|
||||||
|
if priority is None:
|
||||||
|
continue
|
||||||
|
if priority == "":
|
||||||
|
priority = None
|
||||||
|
reason = request.form.get(f"reason_{key_id}", "")
|
||||||
|
used_in_quest = 1 if request.form.get(f"used_in_quest_{key_id}") == "on" else 0
|
||||||
|
map_ids = []
|
||||||
|
for value in request.form.getlist(f"map_ids_{key_id}"):
|
||||||
|
try:
|
||||||
|
map_ids.append(int(value))
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
_update_key(conn, key_id, priority, reason, used_in_quest, map_ids)
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
redirect_args = {}
|
||||||
|
if map_filter:
|
||||||
|
redirect_args["map_id"] = map_filter
|
||||||
|
if sort:
|
||||||
|
redirect_args["sort"] = sort
|
||||||
|
if show:
|
||||||
|
redirect_args["show"] = show
|
||||||
|
base_url = url_for("index", **redirect_args)
|
||||||
|
if save_one:
|
||||||
|
return redirect(f"{base_url}#key-{save_one}")
|
||||||
|
return redirect(base_url)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
form {
|
.filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -98,8 +98,10 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
input[name="reason"] {
|
input[name^="reason_"] {
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
}
|
}
|
||||||
.map-list {
|
.map-list {
|
||||||
@@ -122,6 +124,12 @@
|
|||||||
.quest-flag input {
|
.quest-flag input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.save-all {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 4px 0 16px;
|
||||||
|
}
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
body {
|
body {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
@@ -130,7 +138,8 @@
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
form {
|
.filters,
|
||||||
|
.key-form {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -139,7 +148,7 @@
|
|||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
input[name="reason"] {
|
input[name^="reason_"] {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
@@ -171,11 +180,47 @@
|
|||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
<label for="show">Show</label>
|
||||||
|
<select id="show" name="show">
|
||||||
|
<option value="all" {% if show == "all" %}selected{% endif %}>All</option>
|
||||||
|
<option value="rated" {% if show == "rated" %}selected{% endif %}>Rated</option>
|
||||||
|
<option value="unrated" {% if show == "unrated" %}selected{% endif %}>NR (not rated)</option>
|
||||||
|
<option value="quest" {% if show == "quest" %}selected{% endif %}>Used in quest</option>
|
||||||
|
</select>
|
||||||
|
<label for="sort">Sort</label>
|
||||||
|
<select id="sort" name="sort">
|
||||||
|
<option value="priority_desc" {% if sort == "priority_desc" %}selected{% endif %}>
|
||||||
|
Priority high → low
|
||||||
|
</option>
|
||||||
|
<option value="priority_asc" {% if sort == "priority_asc" %}selected{% endif %}>
|
||||||
|
Priority low → high
|
||||||
|
</option>
|
||||||
|
<option value="name_asc" {% if sort == "name_asc" %}selected{% endif %}>
|
||||||
|
Name A → Z
|
||||||
|
</option>
|
||||||
|
<option value="name_desc" {% if sort == "name_desc" %}selected{% endif %}>
|
||||||
|
Name Z → A
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
<button type="submit">Apply</button>
|
<button type="submit">Apply</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form method="post" action="/rate_all">
|
||||||
|
{% if map_filter %}
|
||||||
|
<input type="hidden" name="map_id" value="{{ map_filter }}">
|
||||||
|
{% endif %}
|
||||||
|
{% if sort %}
|
||||||
|
<input type="hidden" name="sort" value="{{ sort }}">
|
||||||
|
{% endif %}
|
||||||
|
{% if show %}
|
||||||
|
<input type="hidden" name="show" value="{{ show }}">
|
||||||
|
{% endif %}
|
||||||
|
<div class="save-all">
|
||||||
|
<button type="submit" name="save_all" value="1">Save all changes</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% for key in keys %}
|
{% for key in keys %}
|
||||||
<div class="key">
|
<div class="key" id="key-{{ key.id }}">
|
||||||
<img
|
<img
|
||||||
src="{{ key.grid_image_url }}"
|
src="{{ key.grid_image_url }}"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@@ -197,12 +242,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form method="post" action="/rate" class="key-form">
|
<div class="key-form">
|
||||||
<input type="hidden" name="key_id" value="{{ key.id }}">
|
<input type="hidden" name="key_ids" value="{{ key.id }}">
|
||||||
{% if map_filter %}
|
<select name="priority_{{ key.id }}">
|
||||||
<input type="hidden" name="map_id" value="{{ map_filter }}">
|
<option value="" {% if key.priority is none %}selected{% endif %}>NR (not rated)</option>
|
||||||
{% endif %}
|
|
||||||
<select name="priority">
|
|
||||||
{% for i, label in [(0,'IGNORE'),(1,'LOW'),(2,'MED'),(3,'HIGH'),(4,'SUPER')] %}
|
{% for i, label in [(0,'IGNORE'),(1,'LOW'),(2,'MED'),(3,'HIGH'),(4,'SUPER')] %}
|
||||||
<option value="{{ i }}" {% if key.priority == i %}selected{% endif %}>
|
<option value="{{ i }}" {% if key.priority == i %}selected{% endif %}>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
@@ -210,16 +253,16 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<label class="quest-flag">
|
<label class="quest-flag">
|
||||||
<input type="checkbox" name="used_in_quest" {% if key.used_in_quest %}checked{% endif %}>
|
<input type="checkbox" name="used_in_quest_{{ key.id }}" {% if key.used_in_quest %}checked{% endif %}>
|
||||||
<span>Used in quest?</span>
|
<span>Used in quest?</span>
|
||||||
</label>
|
</label>
|
||||||
<input name="reason" placeholder="note…" value="{{ key.reason or '' }}">
|
<input name="reason_{{ key.id }}" placeholder="note…" value="{{ key.reason or '' }}">
|
||||||
<div class="map-list">
|
<div class="map-list">
|
||||||
{% for map in maps %}
|
{% for map in maps %}
|
||||||
<label class="map-checkbox">
|
<label class="map-checkbox">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="map_ids"
|
name="map_ids_{{ key.id }}"
|
||||||
value="{{ map.id }}"
|
value="{{ map.id }}"
|
||||||
{% if map.id in selected_maps %}checked{% endif %}
|
{% if map.id in selected_maps %}checked{% endif %}
|
||||||
>
|
>
|
||||||
@@ -227,11 +270,16 @@
|
|||||||
</label>
|
</label>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<button type="submit">Save</button>
|
<button type="submit" name="save_one" value="{{ key.id }}">Save</button>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="save-all">
|
||||||
|
<button type="submit" name="save_all" value="1">Save all changes</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user