1- from itertools import chain
2-
3- from django .conf import settings
4- from django .core .exceptions import FieldDoesNotExist
5- from django .db .models .fields .related import RelatedField
6-
7- try :
8- from itertools import pairwise
9- except ImportError :
10- # python<3.10 compatability
11- from itertools import tee
12-
13- def pairwise (iterable ):
14- a , b = tee (iterable )
15- next (b , None )
16- return zip (a , b )
17-
18-
19- import htmlgenerator as hg
201from basxbread import layout
212from django .utils .translation import gettext_lazy as _
223
234from basxconnect .core .layouts .editperson .common import utils
245
256R = layout .grid .Row
26- C = layout .grid .Col
27-
28-
29- def changes (c ):
30- if c ["row" ][0 ] is not None and c ["row" ][1 ] is not None :
31- return list (c ["row" ][0 ].diff_against (c ["row" ][1 ]).changes )
32- return ()
33-
34-
35- def haschanges (a , b ):
36- return a is not None and b is not None and len (a .diff_against (b ).changes ) > 0
37-
38-
39- def fieldname (c , model ):
40- try :
41- return model ._meta .get_field (c ["change" ].field ).verbose_name
42- except FieldDoesNotExist :
43- return c ["change" ].field .replace ("_" , " " ).capitalize ()
44-
45-
46- def newfieldvalue (c , model ):
47- try :
48- field = model ._meta .get_field (c ["change" ].field )
49- if isinstance (field , RelatedField ):
50- try :
51- return field .related_model .objects .get (id = int (c ["change" ].new ))
52- except field .related_model .DoesNotExist :
53- return hg .SPAN (_ ("<Value has been deleted>" ), style = "color: red" )
54- except FieldDoesNotExist :
55- pass
56- return c ["change" ].new
57-
58-
59- def oldfieldvalue (c , model ):
60- try :
61- field = model ._meta .get_field (c ["change" ].field )
62- if isinstance (field , RelatedField ):
63- ret = field .related_model .objects .filter (id = int (c ["change" ].old )).first ()
64- return ret or hg .SPAN (_ ("<Value has been deleted>" ), style = "color: red" )
65- except FieldDoesNotExist :
66- pass
67- return c ["change" ].old
68-
69-
70- def diff_table (model , historylist , showObjectLabel = None ):
71- def historyentries (c ):
72- return (
73- (i , j )
74- for i , j in pairwise (chain (historylist (c ), [None ]))
75- if haschanges (i , j )
76- )
77-
78- return layout .components .datatable .DataTable (
79- row_iterator = hg .F (historyentries ),
80- columns = [
81- layout .components .datatable .DataTableColumn (
82- _ ("Date" ),
83- layout .localize (layout .localtime (hg .C ("row" )[0 ].history_date ).date ()),
84- ),
85- layout .components .datatable .DataTableColumn (
86- _ ("Time" ),
87- layout .localize (layout .localtime (hg .C ("row" )[0 ].history_date ).time ()),
88- ),
89- layout .components .datatable .DataTableColumn (
90- _ ("User" ),
91- hg .C ("row" )[0 ].history_user ,
92- ),
93- * (
94- [
95- layout .components .datatable .DataTableColumn (
96- _ ("Object" ),
97- hg .F (lambda c : showObjectLabel (c ["row" ][0 ].instance )),
98- )
99- ]
100- if showObjectLabel is not None
101- else []
102- ),
103- layout .components .datatable .DataTableColumn (
104- _ ("Changes" ),
105- hg .UL (
106- hg .Iterator (
107- hg .F (changes ),
108- "change" ,
109- hg .LI (
110- hg .SPAN (
111- hg .F (lambda c : fieldname (c , model (c ))),
112- style = "font-weight: 600" ,
113- ),
114- ": " ,
115- hg .SPAN (
116- hg .If (
117- hg .C ("change" ).old ,
118- hg .F (lambda c : oldfieldvalue (c , model (c ))),
119- settings .HTML_NONE ,
120- ),
121- style = "text-decoration: line-through;" ,
122- ),
123- " -> " ,
124- hg .SPAN (
125- hg .If (
126- hg .C ("change" ).new ,
127- hg .F (lambda c : newfieldvalue (c , model (c ))),
128- settings .HTML_NONE ,
129- )
130- ),
131- ),
132- ),
133- ),
134- ),
135- ],
136- )
1377
1388
1399def history_tab ():
@@ -152,7 +22,7 @@ def historyentries(c):
15222 utils .grid_inside_tab (
15323 R (
15424 utils .tiling_col (
155- diff_table (
25+ layout . history_table . diff_table (
15626 lambda c : type (c ["object" ]), historyentries
15727 ).with_toolbar (_ ("Changes" ))
15828 )
0 commit comments