summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2021-11-18 12:37:29 -0800
committerBryan Newbold <bnewbold@robocracy.org>2021-11-18 12:37:33 -0800
commit7163f36a5e9f159def223a76953505ffff9a56c7 (patch)
tree2578a54eef3bb079caf4ee86e3ab6b51876ed90e
parente7ad9a390584ac9df0f7c03dc687e38ca4e073e3 (diff)
downloadfatcat-7163f36a5e9f159def223a76953505ffff9a56c7.tar.gz
fatcat-7163f36a5e9f159def223a76953505ffff9a56c7.zip
polish editgroup diff view
Still not as great as it could be, but useful in this state.
-rw-r--r--python/fatcat_web/entity_helpers.py53
-rw-r--r--python/fatcat_web/templates/editgroup_diff.html52
-rw-r--r--python/fatcat_web/templates/editgroup_view.html62
-rw-r--r--python/tests/web_editgroup.py8
4 files changed, 83 insertions, 92 deletions
diff --git a/python/fatcat_web/entity_helpers.py b/python/fatcat_web/entity_helpers.py
index bf81dfce..24f380c8 100644
--- a/python/fatcat_web/entity_helpers.py
+++ b/python/fatcat_web/entity_helpers.py
@@ -1,5 +1,5 @@
import difflib
-from typing import Any, Dict, Tuple
+from typing import Any, Dict, List, Tuple
from fatcat_openapi_client import (
ContainerEntity,
@@ -262,47 +262,52 @@ def generic_get_editgroup_entity(
return entity, edit
-def _entity_edit_diff(entity_type: str, entity_edit: EntityEdit) -> Dict[str, Any]:
+def _entity_edit_diff(entity_type: str, entity_edit: EntityEdit) -> List[str]:
"""
- entity_edit
- ident
- revision
- prev_revision
- redirect_ident
+ Helper to generate diff lines for a single entity edit.
+
+ Schema of entity_edit (as a reminder):
+
+ entity_edit
+ ident
+ revision
+ prev_revision
+ redirect_ident
"""
pop_fields = ["revision", "state"]
new_rev = generic_get_entity_revision(entity_type, entity_edit.revision)
- new_toml = entity_to_toml(new_rev, pop_fields=pop_fields)
+ new_toml = entity_to_toml(new_rev, pop_fields=pop_fields).split("\n")
+ if len(new_toml) == 1 and not new_toml[0].strip():
+ new_toml = []
if entity_edit.prev_revision:
old_rev = generic_get_entity_revision(entity_type, entity_edit.prev_revision)
- old_toml = entity_to_toml(old_rev, pop_fields=pop_fields)
+ old_toml = entity_to_toml(old_rev, pop_fields=pop_fields).split("\n")
fromdesc = f"/{entity_type}/rev/{entity_edit.prev_revision}.toml"
else:
- old_toml = ""
+ old_toml = []
fromdesc = "(created)"
- # differ = difflib.HtmlDiff(tabsize=4)
- # html_table = differ.make_table(
- # old_toml.split('\n'),
- # new_toml.split('\n'),
- # fromdesc=fromdesc,
- # todesc=entity_edit.revision,
- # context=True,
- # numlines=3,
- # )
- # return dict(html_table=html_table)
diff_lines = list(
difflib.unified_diff(
- old_toml.split("\n"),
- new_toml.split("\n"),
+ old_toml,
+ new_toml,
fromfile=fromdesc,
tofile=f"/{entity_type}/rev/{entity_edit.revision}.toml",
)
)
- return dict(diff_lines=diff_lines)
+ return diff_lines
def editgroup_get_diffs(editgroup: Editgroup) -> Dict[str, Any]:
+ """
+ Fetches before/after entity revisions, and computes "diffs" of TOML representations.
+
+ Returns a dict with entity type (pluralized, like "files"), then within
+ that a dict with entity ident (without prefix) containing a list of
+ strings, one per line of the "unified diff" format. If there is no diff for
+ an edited entity (eg, it was or redirected), instead `None` is returned for
+ that entity.
+ """
diffs: Dict[str, Any] = {}
for entity_type in [
@@ -322,6 +327,4 @@ def editgroup_get_diffs(editgroup: Editgroup) -> Dict[str, Any]:
diffs[entity_type][ed.ident] = _entity_edit_diff(entity_type, ed)
else:
diffs[entity_type][ed.ident] = None
- # XXX:
- print(diffs.keys())
return diffs
diff --git a/python/fatcat_web/templates/editgroup_diff.html b/python/fatcat_web/templates/editgroup_diff.html
index de6a800d..4b32fbf5 100644
--- a/python/fatcat_web/templates/editgroup_diff.html
+++ b/python/fatcat_web/templates/editgroup_diff.html
@@ -2,56 +2,31 @@
{% macro edit_diff_list(auth_to, editgroup, edits, diffs, entity_type, entity_name) -%}
{% if edits %}
- <h3>{{ entity_name }} Edits ({{ edits|count }})</h3>
+ <h3>{{ entity_name }} Edit Diffs ({{ edits|count }})</h3>
<hr>
<div class="ui divided list">
{% for edit in edits %}
- <div class="item">
+ <div class="item" id="{{ entity_type }}_{{ edit.ident }}">
<div class="content" style="padding-bottom: 0.5em;">
- <div style="float: right; font-weight: bold;">
- <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}">[view]</a>
- {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %}
- <br><a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}/edit" style="color: green;">[re-edit]</a>
- <br>
- <form id="submit_edit_delete" method="POST" action="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/edit/{{ edit.edit_id }}/delete" style="display:inline;">
- <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
- <input type="submit" value="[delete]" style="background:none; color: red; border: none; font-weight:bold; cursor:pointer; padding: 0;"></input>
- </form>
- {% endif %}
- </div>
- <div class="header">
- <a href="/{{ entity_type }}/{{ edit.ident }}">{{ entity_type }}_{{ edit.ident }}</a>
- {% if edit.redirect_ident %}
- =&gt; redirect to <a href="/{{ entity_type }}/{{ edit.redirect_ident }}">{{ entity_type }}/{{ edit.redirect_ident }}</a>
- {% elif not edit.revision %}
- deleted
- {% elif not edit.prev_revision %}
- created
- {% else %}
- updated
- {% endif %}
- </div>
- {% if edit.revision %}
- Revision: <small><code><a href="/{{ entity_type }}/rev/{{ edit.revision }}">{{ edit.revision }}</a></code></small>
- {% endif %}
+ {{ entity_edit_header(auth_to, editgroup, edit, entity_type, entity_name) }}
{% if edit.extra %}
{{ entity_macros.extra_metadata(edit.extra) }}
{% endif %}
- {% if edit.revision and not edit.redirect_ident and edit.ident in diffs %}
- <div style="border: 2px solid black; overflow-x:scroll; margin: 0.5em;">
- {% for line in diffs[edit.ident]['diff_lines'] %}
+ {% if edit.revision and not edit.redirect_ident and edit.ident in diffs and diffs[edit.ident] != None %}
+ <div style="border: 1px solid black; font-size: smaller; font-color: #222; word-break: break-all; margin-top: 0.5em; margin-bottom: 0.5em;">
+ {% for line in diffs[edit.ident] %}
{% set line_space = false %}
{% if line.startswith('@@') or line.startswith('---') or line.startswith('+++') %}
- {% set line_color = "lightblue" %}
+ {% set line_color = "lightblue" %}{# a light blue #}
{% elif line.startswith('+') %}
- {% set line_color = "lightgreen" %}
+ {% set line_color = "#a4efa4" %}{# a light green #}
{% elif line.startswith('-') %}
- {% set line_color = "#ffa3a3" %}
+ {% set line_color = "#ffa3a3" %}{# a light red #}
{% else %}
- {% set line_color = "#ddd" %}
+ {% set line_color = "#eee" %}{# almost white #}
{% set line_space = true %}
{% endif %}
- <pre style="background-color: {{ line_color }}; margin: 0px;">{% if line_space %} {% endif %}{{ line.strip() }}</pre>
+ <pre style="background-color: {{ line_color }}; white-space: pre-wrap; margin: 0px;">{% if line_space %}&nbsp;{% endif %}{{ line.strip() }}</pre>
{% endfor %}
</div>
{% endif %}
@@ -62,10 +37,11 @@
{% endif %}
{%- endmacro %}
-{% block title %}Editgroup diff{% endblock %}
+{% block title %}Editgroup Diff{% endblock %}
+
+{% block pagetitle %}Editgroup Diff{% endblock %}
{% block editgroupedits %}
-<h3 class="ui header">All Entity Change Diffs</h3>
{{ edit_diff_list(auth_to, editgroup, editgroup.edits.releases, editgroup_diffs.release, "release", "Release") }}
{{ edit_diff_list(auth_to, editgroup, editgroup.edits.works, editgroup_diffs.work, "work", "Work") }}
{{ edit_diff_list(auth_to, editgroup, editgroup.edits.containers, editgroup_diffs.container, "container", "Container") }}
diff --git a/python/fatcat_web/templates/editgroup_view.html b/python/fatcat_web/templates/editgroup_view.html
index de904c2a..0142a46b 100644
--- a/python/fatcat_web/templates/editgroup_view.html
+++ b/python/fatcat_web/templates/editgroup_view.html
@@ -1,40 +1,45 @@
{% extends "base.html" %}
{% import "entity_macros.html" as entity_macros %}
+{% macro entity_edit_header(auth_to, editgroup, edit, entity_type, entity_name) -%}
+ <div style="float: right; font-weight: bold;">
+ <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}">[view]</a>
+ <a href="/editgroup/{{ editgroup.editgroup_id }}/diff#{{ entity_type }}_{{ edit.ident }}">[diff]</a>
+ {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %}
+ <br><a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}/edit" style="color: green;">[re-edit]</a>
+ <br>
+ <form id="submit_edit_delete" method="POST" action="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/edit/{{ edit.edit_id }}/delete" style="display:inline;">
+ <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
+ <input type="submit" value="[delete]" style="background:none; color: red; border: none; font-weight:bold; cursor:pointer; padding: 0;"></input>
+ </form>
+ {% endif %}
+ </div>
+ <div class="header">
+ <a href="/{{ entity_type }}/{{ edit.ident }}">{{ entity_type }}_{{ edit.ident }}</a>
+ {% if edit.redirect_ident %}
+ =&gt; redirect to <a href="/{{ entity_type }}/{{ edit.redirect_ident }}">{{ entity_type }}/{{ edit.redirect_ident }}</a>
+ {% elif not edit.revision %}
+ deleted
+ {% elif not edit.prev_revision %}
+ created
+ {% else %}
+ updated
+ {% endif %}
+ </div>
+ {% if edit.revision %}
+ Revision: <small><code><a href="/{{ entity_type }}/rev/{{ edit.revision }}">{{ edit.revision }}</a></code></small>
+ {% endif %}
+{%- endmacro %}
+
{% macro edit_list(auth_to, editgroup, edits, entity_type, entity_name) -%}
<div class="{% if edits %}active{% endif %} title">
<h3><i class="dropdown icon"></i>{{ entity_name }} Edits ({{ edits|count }})</h3>
</div><div class="{% if edits %}active{% endif %} content" style="padding-bottom: 0.5em;">
<div class="ui divided list">
{% for edit in edits %}
- <div class="item">
+ <div class="item" id="{{ entity_type }}_{{ edit.ident }}">
<div class="content" style="padding-bottom: 0.5em;">
- <div style="float: right; font-weight: bold;">
- <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}">[view]</a>
- {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %}
- <br><a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}/edit" style="color: green;">[re-edit]</a>
- <br>
- <form id="submit_edit_delete" method="POST" action="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/edit/{{ edit.edit_id }}/delete" style="display:inline;">
- <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
- <input type="submit" value="[delete]" style="background:none; color: red; border: none; font-weight:bold; cursor:pointer; padding: 0;"></input>
- </form>
- {% endif %}
- </div>
- <div class="header">
- <a href="/{{ entity_type }}/{{ edit.ident }}">{{ entity_type }}_{{ edit.ident }}</a>
- {% if edit.redirect_ident %}
- =&gt; redirect to <a href="/{{ entity_type }}/{{ edit.redirect_ident }}">{{ entity_type }}/{{ edit.redirect_ident }}</a>
- {% elif not edit.revision %}
- deleted
- {% elif not edit.prev_revision %}
- created
- {% else %}
- updated
- {% endif %}
- </div>
- {% if edit.revision %}
- Revision: <small><code><a href="/{{ entity_type }}/rev/{{ edit.revision }}">{{ edit.revision }}</a></code></small>
- {% endif %}
+ {{ entity_edit_header(auth_to, editgroup, edit, entity_type, entity_name) }}
{% if edit.extra %}
{{ entity_macros.extra_metadata(edit.extra) }}
{% endif %}
@@ -51,11 +56,10 @@
{# extended by changelog_entry #}
{% block editgroupheader %}
-<h1 class="ui header">Editgroup
+<h1 class="ui header">{% block pagetitle %}Editgroup{% endblock %}
<span class="sub header"><code>editgroup_{{ editgroup.editgroup_id }}</code></span></h1>
{% if not auth_to.submit %}
-<br clear="all">
<div class="ui info small message">
<div class="header">
What is an editgroup?
diff --git a/python/tests/web_editgroup.py b/python/tests/web_editgroup.py
index 62a5df2e..906c18e6 100644
--- a/python/tests/web_editgroup.py
+++ b/python/tests/web_editgroup.py
@@ -5,8 +5,16 @@ def test_editgroup_basics(app):
rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaae")
assert rv.status_code == 200
+ rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaae/diff")
+ assert rv.status_code == 200
+ rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaa4/diff")
+ assert rv.status_code == 200
+ rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaaq/diff")
+ assert rv.status_code == 200
rv = app.get("/editgroup/ccccccccccccccccccccccccca")
assert rv.status_code == 404
+ rv = app.get("/editgroup/ccccccccccccccccccccccccca/diff")
+ assert rv.status_code == 404
rv = app.get("/editor/aaaaaaaaaaaabkvkaaaaaaaaae")
assert rv.status_code == 200