lino 24.9.4__py3-none-any.whl → 24.10.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lino/__init__.py +1 -5
- lino/api/doctest.py +29 -6
- lino/core/__init__.py +0 -1
- lino/core/actions.py +16 -9
- lino/core/actors.py +99 -30
- lino/core/choicelists.py +28 -11
- lino/core/constants.py +20 -4
- lino/core/dashboard.py +19 -18
- lino/core/dbtables.py +49 -60
- lino/core/elems.py +26 -33
- lino/core/fields.py +13 -7
- lino/core/kernel.py +3 -3
- lino/core/model.py +5 -2
- lino/core/renderer.py +52 -39
- lino/core/requests.py +876 -299
- lino/core/store.py +17 -17
- lino/core/tables.py +46 -32
- lino/core/utils.py +134 -0
- lino/mixins/dupable.py +1 -1
- lino/modlib/bootstrap3/views.py +4 -3
- lino/modlib/checkdata/models.py +1 -1
- lino/modlib/comments/mixins.py +2 -2
- lino/modlib/comments/ui.py +83 -77
- lino/modlib/dupable/models.py +1 -1
- lino/modlib/export_excel/models.py +0 -3
- lino/modlib/extjs/ext_renderer.py +8 -8
- lino/modlib/extjs/views.py +8 -17
- lino/modlib/forms/views.py +3 -3
- lino/modlib/help/management/commands/makehelp.py +1 -1
- lino/modlib/notify/models.py +1 -1
- lino/modlib/odata/views.py +2 -2
- lino/modlib/printing/actions.py +0 -5
- lino/modlib/publisher/ui.py +3 -3
- lino/modlib/publisher/views.py +14 -11
- lino/modlib/search/models.py +2 -2
- lino/modlib/system/mixins.py +0 -10
- lino/modlib/uploads/mixins.py +6 -3
- lino/modlib/uploads/ui.py +2 -2
- lino/modlib/users/mixins.py +5 -5
- lino/sphinxcontrib/actordoc.py +1 -1
- lino/sphinxcontrib/logo/static/linodocs.css +1 -8
- lino/utils/choosers.py +1 -1
- lino/utils/report.py +4 -11
- {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/METADATA +1 -1
- {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/RECORD +48 -49
- lino/core/tablerequest.py +0 -758
- {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/WHEEL +0 -0
- {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/licenses/COPYING +0 -0
lino/core/dbtables.py
CHANGED
@@ -28,14 +28,13 @@ from lino.core import actions
|
|
28
28
|
from lino.core.model import Model
|
29
29
|
from lino.core import actors
|
30
30
|
from lino.core import constants
|
31
|
-
from lino.core.tablerequest import TableRequest
|
32
31
|
|
33
32
|
from lino.core.choicelists import ChoiceListField
|
34
33
|
from .utils import models_by_base
|
35
34
|
# from .fields import get_data_elem_from_model
|
36
35
|
|
37
36
|
from lino.core.utils import resolve_model, get_field, UnresolvedModel
|
38
|
-
from lino.core.tables import AbstractTable
|
37
|
+
from lino.core.tables import AbstractTable
|
39
38
|
from lino.core.gfks import ContentType, GenericForeignKey
|
40
39
|
|
41
40
|
INVALID_MK = "Invalid master_key '{0}' in {1} : {2}"
|
@@ -129,9 +128,9 @@ def rc_name(rptclass):
|
|
129
128
|
return rptclass.app_label + "." + rptclass.__name__
|
130
129
|
|
131
130
|
|
132
|
-
def has_fk(
|
133
|
-
if isinstance(
|
134
|
-
return
|
131
|
+
def has_fk(ar, name):
|
132
|
+
if isinstance(ar, ActionRequest) and ar.actor is not None:
|
133
|
+
return ar.actor.master_key == name
|
135
134
|
return False
|
136
135
|
|
137
136
|
|
@@ -212,7 +211,6 @@ class Table(AbstractTable):
|
|
212
211
|
|
213
212
|
@classmethod
|
214
213
|
def init_layouts(cls):
|
215
|
-
# if cls.list_layout is None:
|
216
214
|
if cls.model is not None and issubclass(cls.model, Model):
|
217
215
|
if not cls.abstract:
|
218
216
|
for tbl in cls.__mro__:
|
@@ -222,7 +220,7 @@ class Table(AbstractTable):
|
|
222
220
|
if issubclass(tbl, actors.Actor):
|
223
221
|
cls.list_layout = "list_item"
|
224
222
|
break
|
225
|
-
super(
|
223
|
+
super().init_layouts()
|
226
224
|
|
227
225
|
@classmethod
|
228
226
|
def add_quick_search_filter(cls, qs, search_text):
|
@@ -237,7 +235,7 @@ class Table(AbstractTable):
|
|
237
235
|
|
238
236
|
@classmethod
|
239
237
|
def get_chooser_for_field(self, fieldname):
|
240
|
-
ch = super(
|
238
|
+
ch = super().get_chooser_for_field(fieldname)
|
241
239
|
if ch is not None:
|
242
240
|
return ch
|
243
241
|
if self.model is not None:
|
@@ -292,7 +290,7 @@ class Table(AbstractTable):
|
|
292
290
|
for ds in yield_model_detail_sets(self.model):
|
293
291
|
yield ds
|
294
292
|
|
295
|
-
for s in super(
|
293
|
+
for s in super().get_detail_sets():
|
296
294
|
yield s
|
297
295
|
|
298
296
|
# @classmethod
|
@@ -302,25 +300,6 @@ class Table(AbstractTable):
|
|
302
300
|
# return vf
|
303
301
|
# return cls.model._meta.get_field(name)
|
304
302
|
|
305
|
-
@classmethod
|
306
|
-
def get_table_story(cls, obj, ar):
|
307
|
-
sar = cls.request(parent=ar, master_instance=obj, is_on_main_actor=False)
|
308
|
-
html = mark_safe("")
|
309
|
-
for i, obj in enumerate(sar.data_iterator):
|
310
|
-
if i == cls.preview_limit:
|
311
|
-
break
|
312
|
-
s = obj.as_story_item(sar)
|
313
|
-
# assert_safe(s) # temporary 20240506
|
314
|
-
html += s
|
315
|
-
if cls.insert_action is not None:
|
316
|
-
if not cls.editable:
|
317
|
-
return html
|
318
|
-
ir = cls.insert_action.request_from(sar)
|
319
|
-
if ir.get_permission():
|
320
|
-
html = tostring(ir.ar2button()) + html
|
321
|
-
# assert_safe(html) # temporary 20240506
|
322
|
-
return html
|
323
|
-
|
324
303
|
@classmethod
|
325
304
|
def get_pk_field(self):
|
326
305
|
return self.model._meta.pk
|
@@ -334,19 +313,28 @@ class Table(AbstractTable):
|
|
334
313
|
Note: `ar` may not be None.
|
335
314
|
|
336
315
|
"""
|
337
|
-
return self.model.objects.get(pk=pk)
|
316
|
+
# return self.model.objects.get(pk=pk)
|
317
|
+
# raise Exception("20240929")
|
318
|
+
qs = self.get_request_queryset(ar)
|
338
319
|
# qs = self.model.get_request_queryset(ar)
|
339
|
-
#
|
340
|
-
|
341
|
-
#
|
320
|
+
# str(qs.query)
|
321
|
+
|
322
|
+
# return qs.get(pk=pk)
|
323
|
+
try:
|
324
|
+
return qs.get(pk=pk)
|
342
325
|
# except ValueError:
|
343
326
|
# return None
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
327
|
+
except self.model.DoesNotExist:
|
328
|
+
# sql = qs.query
|
329
|
+
# import sqlparse
|
330
|
+
# sql = str(sql).replace('"', '')
|
331
|
+
# sql = sqlparse.format(sql, reindent=True, keyword_case='upper')
|
332
|
+
# raise self.model.DoesNotExist(f"No row {pk} in {ar} ({sql})")
|
333
|
+
raise self.model.DoesNotExist(f"No row {pk} in {ar}") from None
|
334
|
+
# from django.core.exceptions import ObjectDoesNotExist
|
335
|
+
# assert isinstance(exc, ObjectDoesNotExist)
|
336
|
+
# raise exc
|
337
|
+
# return None
|
350
338
|
|
351
339
|
# @classmethod
|
352
340
|
# def disabled_actions(self, ar, obj): # no longer used since 20170909
|
@@ -520,7 +508,7 @@ class Table(AbstractTable):
|
|
520
508
|
self.master_field = fk
|
521
509
|
# self.hidden_columns |= set([fk.name])
|
522
510
|
|
523
|
-
super(
|
511
|
+
super().class_init()
|
524
512
|
|
525
513
|
if self.order_by is not None:
|
526
514
|
if not isinstance(self.order_by, (list, tuple)):
|
@@ -547,7 +535,7 @@ class Table(AbstractTable):
|
|
547
535
|
|
548
536
|
@classmethod
|
549
537
|
def do_setup(self):
|
550
|
-
super(
|
538
|
+
super().do_setup()
|
551
539
|
# AbstractTable.do_setup(self)
|
552
540
|
if self.model is None:
|
553
541
|
return
|
@@ -567,7 +555,7 @@ class Table(AbstractTable):
|
|
567
555
|
|
568
556
|
@classmethod
|
569
557
|
def make_disabled_fields(cls, obj, ar):
|
570
|
-
s = super(
|
558
|
+
s = super().make_disabled_fields(obj, ar)
|
571
559
|
|
572
560
|
if obj is not None and ar is not None:
|
573
561
|
s |= obj.disabled_fields(ar)
|
@@ -605,8 +593,7 @@ class Table(AbstractTable):
|
|
605
593
|
if self.delete_action is None:
|
606
594
|
return "No delete_action"
|
607
595
|
if not self.get_row_permission(
|
608
|
-
obj, ar, self.get_row_state(obj), self.delete_action
|
609
|
-
):
|
596
|
+
obj, ar, self.get_row_state(obj), self.delete_action):
|
610
597
|
# print "20130222 ar is %r" % ar
|
611
598
|
# logger.info("20130225 dbtables.disable_delete no permission")
|
612
599
|
return _("You have no permission to delete this row.")
|
@@ -634,23 +621,25 @@ class Table(AbstractTable):
|
|
634
621
|
qs = qs.exclude(**ar.exclude)
|
635
622
|
# qs = qs.exclude(ar.exclude)
|
636
623
|
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
624
|
+
if ar.param_values is not None:
|
625
|
+
spv = dict()
|
626
|
+
for k in self.simple_parameters:
|
627
|
+
v = getattr(ar.param_values, k)
|
628
|
+
# if "room" in k:
|
629
|
+
# print("20200423", k, v, self.simple_parameters, ar.param_values)
|
630
|
+
if v == constants.CHOICES_BLANK_FILTER_VALUE:
|
631
|
+
spv[k + "__isnull"] = True
|
632
|
+
elif v == constants.CHOICES_NOT_BLANK_FILTER_VALUE:
|
633
|
+
spv[k + "__isnull"] = False
|
634
|
+
elif v is not None:
|
635
|
+
spv[k] = v
|
636
|
+
# print("20240506 {} = {}".format(k, v))
|
637
|
+
# e.g. in MyTickets 'user' should be an obvious field
|
638
|
+
# 20241004 caused #5768:
|
639
|
+
ar.known_values[k] = v # make it an obvious field
|
640
|
+
|
641
|
+
qs = self.model.add_param_filter(qs, **spv)
|
642
|
+
# qs = self.model.add_param_filter(qs, **ar.param_values)
|
654
643
|
|
655
644
|
if self.filter:
|
656
645
|
qs = qs.filter(self.filter)
|
lino/core/elems.py
CHANGED
@@ -854,11 +854,11 @@ class TextFieldElement(FieldElement):
|
|
854
854
|
|
855
855
|
def get_field_options(self, **kw):
|
856
856
|
kw = super().get_field_options(**kw)
|
857
|
-
if isinstance(self.field, fields.VirtualField) and self.field.simple_elem:
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
857
|
+
# if isinstance(self.field, fields.VirtualField) and self.field.simple_elem:
|
858
|
+
# kw["virtualField"] = True
|
859
|
+
# kw["noHeaderDecore"] = True
|
860
|
+
# kw["noEditorHeader"] = True
|
861
|
+
# kw["alwaysEditable"] = True
|
862
862
|
kw["format"] = self.format
|
863
863
|
return kw
|
864
864
|
|
@@ -2311,8 +2311,8 @@ class Panel(Container):
|
|
2311
2311
|
|
2312
2312
|
|
2313
2313
|
class GridElement(Container):
|
2314
|
-
"""Represents a Lino.GridPanel, i.e. the widget used to
|
2315
|
-
table
|
2314
|
+
"""Represents a Lino.GridPanel, i.e. the widget used to render a
|
2315
|
+
table in :term:`grid mode`.
|
2316
2316
|
|
2317
2317
|
"""
|
2318
2318
|
|
@@ -2343,14 +2343,13 @@ class GridElement(Container):
|
|
2343
2343
|
self.actor = rpt
|
2344
2344
|
if len(columns) == 0:
|
2345
2345
|
self.rh = rpt.get_handle()
|
2346
|
-
if not hasattr(self.rh, "
|
2346
|
+
if not hasattr(self.rh, "grid_layout"):
|
2347
2347
|
raise Exception(
|
2348
|
-
"Handle for {0} (model {1}) has no
|
2348
|
+
"Handle for {0} (model {1}) has no grid_layout".format(
|
2349
2349
|
rpt, rpt.model
|
2350
2350
|
)
|
2351
2351
|
)
|
2352
|
-
columns = self.rh.
|
2353
|
-
# columns = self.rh.list_layout._main.elements
|
2352
|
+
columns = self.rh.grid_layout.main.columns
|
2354
2353
|
w = 0
|
2355
2354
|
for e in columns:
|
2356
2355
|
w += e.width or e.preferred_width
|
@@ -2433,20 +2432,15 @@ class SlaveContainer(GridElement):
|
|
2433
2432
|
slaves = None
|
2434
2433
|
|
2435
2434
|
def __init__(self, layout_handle, name, rpt, *columns, **kw):
|
2436
|
-
dms = [dm[1] for dm in rpt.display_mode]
|
2437
2435
|
slaves = dict()
|
2438
|
-
if constants.DISPLAY_MODE_STORY in
|
2436
|
+
if constants.DISPLAY_MODE_STORY in rpt.extra_display_modes:
|
2439
2437
|
slaves["story"] = get_story_element(layout_handle, rpt, name, **kw)
|
2440
|
-
if constants.DISPLAY_MODE_LIST in
|
2438
|
+
if constants.DISPLAY_MODE_LIST in rpt.extra_display_modes:
|
2441
2439
|
slaves["list"] = get_list_element(layout_handle, rpt, name, **kw)
|
2442
|
-
|
2443
|
-
|
2444
|
-
|
2445
|
-
|
2446
|
-
# slaves["story"] = get_story_element(layout_handle, rpt, name, **kw)
|
2447
|
-
# slaves["list"] = get_list_element(layout_handle, rpt, name, **kw)
|
2448
|
-
slaves["html"] = get_htmlbox_element(layout_handle, rpt, name, **kw)
|
2449
|
-
slaves["summary"] = get_summary_element(layout_handle, rpt, name, **kw)
|
2440
|
+
if constants.DISPLAY_MODE_SUMMARY in rpt.extra_display_modes:
|
2441
|
+
slaves["summary"] = get_summary_element(layout_handle, rpt, name, **kw)
|
2442
|
+
if constants.DISPLAY_MODE_HTML in rpt.extra_display_modes:
|
2443
|
+
slaves["html"] = get_htmlbox_element(layout_handle, rpt, name, **kw)
|
2450
2444
|
if slaves:
|
2451
2445
|
self.slaves = slaves
|
2452
2446
|
super().__init__(layout_handle, name, rpt, *columns, **kw)
|
@@ -2845,13 +2839,11 @@ def create_layout_element(lh, name, **kw):
|
|
2845
2839
|
|
2846
2840
|
# print("20240317", de, lh)
|
2847
2841
|
if isinstance(lh.layout, FormLayout):
|
2848
|
-
# When a table is specified in the layout of a
|
2849
|
-
#
|
2850
|
-
#
|
2851
|
-
#
|
2852
|
-
#
|
2853
|
-
# `display_mode` of the table.
|
2854
|
-
|
2842
|
+
# When a table is specified in the layout of a DetailWindow, then it
|
2843
|
+
# will be rendered as a :term:`slave panel`. The panel will have a
|
2844
|
+
# tool button to "open that table in its own window". The display
|
2845
|
+
# mode of that summary is defined by the `default_display_modes` of
|
2846
|
+
# the table.
|
2855
2847
|
if lh.ui.renderer.extjs_version is not None:
|
2856
2848
|
if de.label is not None:
|
2857
2849
|
js = (
|
@@ -2871,17 +2863,18 @@ def create_layout_element(lh, name, **kw):
|
|
2871
2863
|
kw.update(label="{} {}".format(de.get_label(), tostring(btn)))
|
2872
2864
|
|
2873
2865
|
if (
|
2874
|
-
len(de.
|
2866
|
+
len(de.default_display_modes) > 1
|
2875
2867
|
and lh.ui.renderer.front_end.media_name == "react"
|
2876
2868
|
):
|
2869
|
+
# print(f"20240928 {de} in {lh} gets SlaveContainer")
|
2877
2870
|
return SlaveContainer(lh, name, de, **kw)
|
2878
2871
|
|
2879
2872
|
dm = de.get_display_mode()
|
2880
|
-
if dm in
|
2881
|
-
constants.
|
2873
|
+
if dm in {
|
2874
|
+
constants.DISPLAY_MODE_GRID,
|
2882
2875
|
constants.DISPLAY_MODE_CARDS,
|
2883
2876
|
constants.DISPLAY_MODE_GALLERY
|
2884
|
-
|
2877
|
+
}:
|
2885
2878
|
kw.update(hide_top_toolbar=True)
|
2886
2879
|
if de.preview_limit is not None:
|
2887
2880
|
kw.update(preview_limit=de.preview_limit)
|
lino/core/fields.py
CHANGED
@@ -322,7 +322,7 @@ class FakeField(object):
|
|
322
322
|
setattr(self, k, v)
|
323
323
|
|
324
324
|
def __repr__(self):
|
325
|
-
# copied from django Field
|
325
|
+
# copied from django Field
|
326
326
|
path = "%s.%s" % (self.__class__.__module__, self.__class__.__qualname__)
|
327
327
|
name = getattr(self, "name", None)
|
328
328
|
if name is not None:
|
@@ -561,10 +561,10 @@ class VirtualField(FakeField):
|
|
561
561
|
(because they inherit from that class).
|
562
562
|
"""
|
563
563
|
|
564
|
-
simple_elem = False
|
565
|
-
"""
|
566
|
-
Used in :meth:`get_field_options` to set :term:`front end` rendering options.
|
567
|
-
"""
|
564
|
+
# simple_elem = False
|
565
|
+
# """
|
566
|
+
# Used in :meth:`get_field_options` to set :term:`front end` rendering options.
|
567
|
+
# """
|
568
568
|
|
569
569
|
def __init__(self, return_type, get=return_none, **kwargs):
|
570
570
|
"""
|
@@ -579,7 +579,7 @@ class VirtualField(FakeField):
|
|
579
579
|
self.return_type = return_type # a Django Field instance
|
580
580
|
self.get = get
|
581
581
|
|
582
|
-
self.simple_elem = kwargs.get("simple_elem", self.simple_elem)
|
582
|
+
# self.simple_elem = kwargs.get("simple_elem", self.simple_elem)
|
583
583
|
|
584
584
|
# if isinstance(return_type, FakeField):
|
585
585
|
# sortable_by = return_type.sortable_by
|
@@ -1217,6 +1217,12 @@ class TableRow(object):
|
|
1217
1217
|
|
1218
1218
|
_lino_default_table = None
|
1219
1219
|
_widget_options = {}
|
1220
|
+
extra_display_modes = None
|
1221
|
+
"""
|
1222
|
+
A set of extra display modes to make available on actors that use this model.
|
1223
|
+
|
1224
|
+
See :ref:`dg.dd.table.extra_display_modes`.
|
1225
|
+
"""
|
1220
1226
|
|
1221
1227
|
pk = None
|
1222
1228
|
|
@@ -1363,7 +1369,7 @@ class TableRow(object):
|
|
1363
1369
|
return tostring(self.as_summary_item(ar, **kwargs))
|
1364
1370
|
|
1365
1371
|
def as_story_item(self, ar, **kwargs):
|
1366
|
-
kwargs.update(display_mode=
|
1372
|
+
kwargs.update(display_mode=constants.DISPLAY_MODE_STORY)
|
1367
1373
|
return mark_safe("".join(self.as_page(ar, **kwargs)))
|
1368
1374
|
|
1369
1375
|
def as_page(self, ar, **kwargs):
|
lino/core/kernel.py
CHANGED
@@ -877,12 +877,12 @@ class Kernel(object):
|
|
877
877
|
|
878
878
|
if isinstance(h, tables.TableHandle):
|
879
879
|
he = set(h.actor.hidden_columns | h.actor.hidden_elements)
|
880
|
-
|
880
|
+
gl = layouts.ColumnsLayout(
|
881
881
|
h.actor.get_column_names(ar), h.actor, hidden_elements=he
|
882
882
|
)
|
883
|
-
h.
|
883
|
+
h.grid_layout = gl.get_layout_handle()
|
884
884
|
else:
|
885
|
-
h.
|
885
|
+
h.grid_layout = None
|
886
886
|
|
887
887
|
if h.actor.params_layout:
|
888
888
|
h.params_layout_handle = h.actor.make_params_layout_handle()
|
lino/core/model.py
CHANGED
@@ -33,7 +33,8 @@ from .utils import obj2unicode
|
|
33
33
|
from .utils import class_dict_items
|
34
34
|
from .signals import receiver, on_ui_created, pre_ui_delete, pre_ui_save, post_ui_save
|
35
35
|
from .workflows import ChangeStateAction
|
36
|
-
from .
|
36
|
+
from .requests import ActionRequest, sliced_data_iterator
|
37
|
+
from .tables import AbstractTable
|
37
38
|
|
38
39
|
try:
|
39
40
|
import bleach
|
@@ -633,7 +634,8 @@ class Model(models.Model, fields.TableRow):
|
|
633
634
|
|
634
635
|
@fields.htmlbox()
|
635
636
|
def navigation_panel(self, ar):
|
636
|
-
if not isinstance(ar,
|
637
|
+
# if not isinstance(ar, ActionRequest):
|
638
|
+
if ar is None or ar.actor is None or not issubclass(ar.actor, AbstractTable):
|
637
639
|
return None
|
638
640
|
items = []
|
639
641
|
navinfo = ar.actor.get_navinfo(ar, self)
|
@@ -937,6 +939,7 @@ LINO_MODEL_ATTRIBS = (
|
|
937
939
|
"save_watched_instance",
|
938
940
|
"save_existing_instance",
|
939
941
|
"_widget_options",
|
942
|
+
"extra_display_modes",
|
940
943
|
"set_widget_options",
|
941
944
|
"get_widget_options",
|
942
945
|
"get_chooser_for_field",
|
lino/core/renderer.py
CHANGED
@@ -197,7 +197,7 @@ class HtmlRenderer(Renderer):
|
|
197
197
|
import rstgen
|
198
198
|
|
199
199
|
if display_mode == constants.DISPLAY_MODE_CARDS:
|
200
|
-
layout = ar.actor.card_layout or actor.list_layout
|
200
|
+
layout = ar.actor.card_layout or ar.actor.list_layout
|
201
201
|
lh = layout.get_layout_handle()
|
202
202
|
else:
|
203
203
|
lh = ar.bound_action.get_layout_handel()
|
@@ -275,14 +275,18 @@ class HtmlRenderer(Renderer):
|
|
275
275
|
Silently ignores the parameters `stripped` and `header_links`
|
276
276
|
since for HTML these options have no meaning.
|
277
277
|
"""
|
278
|
-
# print("20231227")
|
279
278
|
if display_mode is None:
|
280
279
|
display_mode = ar.actor.get_display_mode()
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
280
|
+
if nosummary and display_mode == constants.DISPLAY_MODE_SUMMARY:
|
281
|
+
display_mode = constants.DISPLAY_MODE_GRID
|
282
|
+
else:
|
283
|
+
assert display_mode in ar.actor.extra_display_modes | constants.BASIC_DISPLAY_MODES
|
284
|
+
if nosummary:
|
285
|
+
raise Exception("Both nosummary and display_mode were specified")
|
286
|
+
|
287
|
+
if display_mode == constants.DISPLAY_MODE_SUMMARY:
|
288
|
+
yield ar.actor.get_table_summary(ar.master_instance, ar)
|
289
|
+
return
|
286
290
|
|
287
291
|
if header_level is not None:
|
288
292
|
k = "h" + str(header_level)
|
@@ -294,6 +298,10 @@ class HtmlRenderer(Renderer):
|
|
294
298
|
yield ar.actor.get_table_as_list(ar.master_instance, ar)
|
295
299
|
return
|
296
300
|
|
301
|
+
if display_mode == constants.DISPLAY_MODE_STORY:
|
302
|
+
yield ar.actor.get_table_story(ar.master_instance, ar)
|
303
|
+
return
|
304
|
+
|
297
305
|
yield ar.table2xhtml(**kwargs)
|
298
306
|
|
299
307
|
# if show_toolbar:
|
@@ -434,7 +442,7 @@ class HtmlRenderer(Renderer):
|
|
434
442
|
def quick_add_buttons(self, ar):
|
435
443
|
"""Returns a HTML chunk that displays "quick add buttons" for the
|
436
444
|
given :class:`action request
|
437
|
-
<lino.core.
|
445
|
+
<lino.core.request.ActionRequest>`: a button :guilabel:`[New]`
|
438
446
|
followed possibly (if the request has rows) by a
|
439
447
|
:guilabel:`[Show last]` and a :guilabel:`[Show all]` button.
|
440
448
|
|
@@ -621,7 +629,7 @@ class HtmlRenderer(Renderer):
|
|
621
629
|
|
622
630
|
"""
|
623
631
|
from lino.core.actors import Actor
|
624
|
-
from lino.core.tables import
|
632
|
+
from lino.core.tables import AbstractTable
|
625
633
|
from lino.core.requests import ActionRequest
|
626
634
|
# print(f"20240908 show_story {ar}")
|
627
635
|
|
@@ -638,19 +646,18 @@ class HtmlRenderer(Renderer):
|
|
638
646
|
ar = item.default_action.request(parent=ar)
|
639
647
|
# 20200501 elems.extend(self.table2story(ar, **kwargs))
|
640
648
|
elems += [tostring(e) for e in self.table2story(ar, **kwargs)]
|
641
|
-
elif isinstance(item, TableRequest):
|
642
|
-
# print(f"20240908 TableRequest {item}")
|
643
|
-
assert item.renderer is not None
|
644
|
-
# 20200501 elems.extend(self.table2story(item, **kwargs))
|
645
|
-
elems += [tostring(e)
|
646
|
-
for e in self.table2story(item, **kwargs)]
|
647
649
|
elif isinstance(item, ActionRequest):
|
648
|
-
# example : courses.StatusReport in dashboard
|
649
650
|
assert item.renderer is not None
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
651
|
+
if issubclass(item.actor, AbstractTable):
|
652
|
+
# 20200501 elems.extend(self.table2story(item, **kwargs))
|
653
|
+
elems += [tostring(e)
|
654
|
+
for e in self.table2story(item, **kwargs)]
|
655
|
+
else:
|
656
|
+
# example : courses.StatusReport in dashboard
|
657
|
+
# 20200501 elems.append(self.show_story(ar, item.actor.get_story(None, ar), **kwargs))
|
658
|
+
elems += [tostring(e)
|
659
|
+
for e in self.show_story(
|
660
|
+
ar, item.actor.get_story(None, ar), **kwargs)]
|
654
661
|
elif isinstance(item, DashboardItem):
|
655
662
|
elems.extend(item.render(ar, **kwargs))
|
656
663
|
# elems += [tostring(e) for e in item.render(ar, **kwargs)]
|
@@ -810,7 +817,7 @@ class TextRenderer(HtmlRenderer):
|
|
810
817
|
stripped=True,
|
811
818
|
show_urls=False,
|
812
819
|
display_mode=None,
|
813
|
-
**kwargs
|
820
|
+
**kwargs
|
814
821
|
):
|
815
822
|
"""
|
816
823
|
Render the given table request as reStructuredText to stdout. See
|
@@ -819,19 +826,24 @@ class TextRenderer(HtmlRenderer):
|
|
819
826
|
self.show_urls = show_urls
|
820
827
|
if display_mode is None:
|
821
828
|
display_mode = ar.actor.get_display_mode()
|
822
|
-
|
823
|
-
|
829
|
+
if nosummary and display_mode == constants.DISPLAY_MODE_SUMMARY:
|
830
|
+
display_mode = constants.DISPLAY_MODE_GRID
|
831
|
+
else:
|
832
|
+
if display_mode not in ar.actor.extra_display_modes | constants.BASIC_DISPLAY_MODES:
|
833
|
+
raise Exception(f"Invalid display mode {display_mode} for {ar.actor}")
|
834
|
+
if nosummary:
|
835
|
+
raise Exception("Both nosummary and display_mode were specified")
|
836
|
+
# print(f"20240929 {nosummary} {display_mode} {ar}")
|
824
837
|
# yield "20240506 {}".format(ar)
|
825
|
-
if
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
return
|
838
|
+
if display_mode == constants.DISPLAY_MODE_SUMMARY:
|
839
|
+
s = to_rst(
|
840
|
+
ar.actor.get_table_summary(ar.master_instance, ar),
|
841
|
+
stripped=stripped,
|
842
|
+
)
|
843
|
+
if stripped:
|
844
|
+
s = s.strip()
|
845
|
+
yield s
|
846
|
+
return
|
835
847
|
|
836
848
|
if display_mode == constants.DISPLAY_MODE_CARDS:
|
837
849
|
for row in ar.sliced_data_iterator:
|
@@ -919,7 +931,7 @@ class TextRenderer(HtmlRenderer):
|
|
919
931
|
def show_story(self, ar, story, stripped=True, **kwargs):
|
920
932
|
"""Render the given story as reStructuredText to stdout."""
|
921
933
|
from lino.core.actors import Actor
|
922
|
-
from lino.core.tables import
|
934
|
+
from lino.core.tables import AbstractTable
|
923
935
|
from lino.core.requests import ActionRequest
|
924
936
|
|
925
937
|
try:
|
@@ -931,13 +943,14 @@ class TextRenderer(HtmlRenderer):
|
|
931
943
|
self.show_table(ar, stripped=stripped, **kwargs)
|
932
944
|
elif isinstance(item, DashboardItem):
|
933
945
|
self.show_story(ar, item.get_story(ar), stripped, **kwargs)
|
934
|
-
elif isinstance(item, TableRequest):
|
935
|
-
self.show_table(item, stripped=stripped, **kwargs)
|
936
|
-
# print(item.table2rst(*args, **kwargs))
|
937
946
|
elif isinstance(item, ActionRequest):
|
938
|
-
# example : courses.StatusReport in dashboard
|
939
947
|
assert item.renderer is not None
|
940
|
-
|
948
|
+
if issubclass(item.actor, AbstractTable):
|
949
|
+
self.show_table(item, stripped=stripped, **kwargs)
|
950
|
+
# print(item.table2rst(*args, **kwargs))
|
951
|
+
else:
|
952
|
+
# example : courses.StatusReport in dashboard
|
953
|
+
self.show_story(ar, item.actor.get_story(None, ar), **kwargs)
|
941
954
|
elif isiterable(item):
|
942
955
|
self.show_story(ar, item, stripped, **kwargs)
|
943
956
|
# for i in self.show_story(ar, item, *args, **kwargs):
|