fix: render human-friendly datetime for such fields in version diff
still render the "raw" value but include human-friendly for convenience
This commit is contained in:
parent
6f26120640
commit
d08ba5fe51
2 changed files with 119 additions and 5 deletions
|
|
@ -25,6 +25,7 @@ Tools for displaying simple data diffs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
from pyramid.renderers import render
|
from pyramid.renderers import render
|
||||||
from webhelpers2.html import HTML
|
from webhelpers2.html import HTML
|
||||||
|
|
@ -150,6 +151,25 @@ class VersionDiff(WebDiff):
|
||||||
# be embedded within a more complex result.
|
# be embedded within a more complex result.
|
||||||
text = HTML.tag("span", c=[repr(value)], style="font-family: monospace;")
|
text = HTML.tag("span", c=[repr(value)], style="font-family: monospace;")
|
||||||
|
|
||||||
|
# style to apply for bold human-friendly text (if applicable)
|
||||||
|
bold = "margin-left: 2rem; font-style: italic; font-weight: bold;"
|
||||||
|
|
||||||
|
# check for standard datetime field
|
||||||
|
if self.mapper.has_property(field):
|
||||||
|
prop = self.mapper.get_property(field)
|
||||||
|
if isinstance(prop, orm.ColumnProperty):
|
||||||
|
if len(prop.columns) == 1:
|
||||||
|
col = prop.columns[0]
|
||||||
|
if isinstance(col.type, sa.DateTime):
|
||||||
|
if value:
|
||||||
|
# render as local datetime w/ "time since" tooltip
|
||||||
|
display = HTML.tag(
|
||||||
|
"span",
|
||||||
|
c=self.app.render_datetime(value, html=True),
|
||||||
|
style=bold,
|
||||||
|
)
|
||||||
|
return HTML.tag("span", c=[text, display])
|
||||||
|
|
||||||
# loop thru all mapped relationship props
|
# loop thru all mapped relationship props
|
||||||
for prop in self.mapper.relationships:
|
for prop in self.mapper.relationships:
|
||||||
|
|
||||||
|
|
@ -176,12 +196,9 @@ class VersionDiff(WebDiff):
|
||||||
if ref := getattr(ref, "version_parent", None):
|
if ref := getattr(ref, "version_parent", None):
|
||||||
|
|
||||||
# render text w/ related object as bold string
|
# render text w/ related object as bold string
|
||||||
style = (
|
|
||||||
"margin-left: 2rem; font-style: italic; font-weight: bold;"
|
|
||||||
)
|
|
||||||
return HTML.tag(
|
return HTML.tag(
|
||||||
"span",
|
"span",
|
||||||
c=[text, HTML.tag("span", c=[str(ref)], style=style)],
|
c=[text, HTML.tag("span", c=[str(ref)], style=bold)],
|
||||||
)
|
)
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- coding: utf-8; -*-
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
|
from wuttjamaican.util import get_timezone_by_name
|
||||||
|
|
||||||
from wuttaweb import diffs as mod
|
from wuttaweb import diffs as mod
|
||||||
from wuttaweb.testing import WebTestCase, VersionWebTestCase
|
from wuttaweb.testing import WebTestCase, VersionWebTestCase
|
||||||
|
|
||||||
|
|
@ -70,7 +79,7 @@ class TestVersionDiff(VersionWebTestCase):
|
||||||
["active", "person_uuid", "prevent_edit", "username", "uuid"],
|
["active", "person_uuid", "prevent_edit", "username", "uuid"],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_render_version_value(self):
|
def test_render_version_value_with_objref(self):
|
||||||
import sqlalchemy_continuum as continuum
|
import sqlalchemy_continuum as continuum
|
||||||
|
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
|
@ -130,3 +139,91 @@ class TestVersionDiff(VersionWebTestCase):
|
||||||
self.assertIn(str(person.uuid), html)
|
self.assertIn(str(person.uuid), html)
|
||||||
self.assertIn("Fred Flintstone", html)
|
self.assertIn("Fred Flintstone", html)
|
||||||
self.assertEqual(diff.render_new_value("person_uuid"), "")
|
self.assertEqual(diff.render_new_value("person_uuid"), "")
|
||||||
|
|
||||||
|
def test_render_version_value_with_datetime(self):
|
||||||
|
import sqlalchemy_continuum as continuum
|
||||||
|
|
||||||
|
tzlocal = get_timezone_by_name("America/Los_Angeles")
|
||||||
|
with patch.object(self.app, "get_timezone", return_value=tzlocal):
|
||||||
|
|
||||||
|
# make one person
|
||||||
|
model = self.app.model
|
||||||
|
person = model.Person(full_name="Fred Flintstone")
|
||||||
|
self.session.add(person)
|
||||||
|
self.session.commit()
|
||||||
|
|
||||||
|
# get its one version record
|
||||||
|
txncls = continuum.transaction_class(model.Person)
|
||||||
|
vercls = continuum.version_class(model.Person)
|
||||||
|
version = self.session.query(vercls).order_by(vercls.transaction_id).one()
|
||||||
|
|
||||||
|
# make a diff, but we have to mock some things up for the test
|
||||||
|
# coverage, since we don't currently have a versioned datetime
|
||||||
|
# field in the base model.
|
||||||
|
diff = self.make_diff(version)
|
||||||
|
|
||||||
|
mock_column = sa.Column("timestamp", sa.DateTime())
|
||||||
|
mock_property = orm.ColumnProperty(column=mock_column)
|
||||||
|
|
||||||
|
class MockMapper:
|
||||||
|
def __init__(self, mapper):
|
||||||
|
self.mapper = mapper
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if hasattr(self.mapper, name):
|
||||||
|
return getattr(self.mapper, name)
|
||||||
|
raise AttributeError(f"attr not found: {name}")
|
||||||
|
|
||||||
|
def has_property(self, field):
|
||||||
|
if field == "timestamp":
|
||||||
|
return True
|
||||||
|
return self.mapper.has_property(field)
|
||||||
|
|
||||||
|
def get_property(self, field):
|
||||||
|
if field == "timestamp":
|
||||||
|
return mock_property
|
||||||
|
return self.mapper.get_property(field)
|
||||||
|
|
||||||
|
mock_mapper = MockMapper(diff.mapper)
|
||||||
|
with patch.object(diff, "mapper", new=mock_mapper):
|
||||||
|
|
||||||
|
# zone-aware local time
|
||||||
|
dt = datetime.datetime(2026, 3, 14, 14, 0, tzinfo=tzlocal)
|
||||||
|
html = diff.render_version_value(version, "timestamp", dt)
|
||||||
|
self.assertTrue(
|
||||||
|
re.search(
|
||||||
|
r'<span style="[^"]+"><span title="[^"]+">\d{4}-\d{2}-\d{2} \d{2}:\d{2}-\d{4}</span></span>',
|
||||||
|
html,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
re.search(
|
||||||
|
r'<span style="[^"]+"><span title="[^"]+">2026-03-14 14:00-0700</span></span>',
|
||||||
|
html,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# zone-naive (presumed UTC)
|
||||||
|
dt = datetime.datetime(2026, 3, 14, 21, 0)
|
||||||
|
html = diff.render_version_value(version, "timestamp", dt)
|
||||||
|
self.assertTrue(
|
||||||
|
re.search(
|
||||||
|
r'<span style="[^"]+"><span title="[^"]+">\d{4}-\d{2}-\d{2} \d{2}:\d{2}-\d{4}</span></span>',
|
||||||
|
html,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
re.search(
|
||||||
|
r'<span style="[^"]+"><span title="[^"]+">2026-03-14 14:00-0700</span></span>',
|
||||||
|
html,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# null
|
||||||
|
html = diff.render_version_value(version, "timestamp", None)
|
||||||
|
self.assertFalse(
|
||||||
|
re.search(
|
||||||
|
r'<span style="[^"]+"><span title="[^"]+">\d{4}-\d{2}-\d{2} \d{2}:\d{2}-\d{4}</span></span>',
|
||||||
|
html,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue