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.
Files changed (49) hide show
  1. lino/__init__.py +1 -5
  2. lino/api/doctest.py +29 -6
  3. lino/core/__init__.py +0 -1
  4. lino/core/actions.py +16 -9
  5. lino/core/actors.py +99 -30
  6. lino/core/choicelists.py +28 -11
  7. lino/core/constants.py +20 -4
  8. lino/core/dashboard.py +19 -18
  9. lino/core/dbtables.py +49 -60
  10. lino/core/elems.py +26 -33
  11. lino/core/fields.py +13 -7
  12. lino/core/kernel.py +3 -3
  13. lino/core/model.py +5 -2
  14. lino/core/renderer.py +52 -39
  15. lino/core/requests.py +876 -299
  16. lino/core/store.py +17 -17
  17. lino/core/tables.py +46 -32
  18. lino/core/utils.py +134 -0
  19. lino/mixins/dupable.py +1 -1
  20. lino/modlib/bootstrap3/views.py +4 -3
  21. lino/modlib/checkdata/models.py +1 -1
  22. lino/modlib/comments/mixins.py +2 -2
  23. lino/modlib/comments/ui.py +83 -77
  24. lino/modlib/dupable/models.py +1 -1
  25. lino/modlib/export_excel/models.py +0 -3
  26. lino/modlib/extjs/ext_renderer.py +8 -8
  27. lino/modlib/extjs/views.py +8 -17
  28. lino/modlib/forms/views.py +3 -3
  29. lino/modlib/help/management/commands/makehelp.py +1 -1
  30. lino/modlib/notify/models.py +1 -1
  31. lino/modlib/odata/views.py +2 -2
  32. lino/modlib/printing/actions.py +0 -5
  33. lino/modlib/publisher/ui.py +3 -3
  34. lino/modlib/publisher/views.py +14 -11
  35. lino/modlib/search/models.py +2 -2
  36. lino/modlib/system/mixins.py +0 -10
  37. lino/modlib/uploads/mixins.py +6 -3
  38. lino/modlib/uploads/ui.py +2 -2
  39. lino/modlib/users/mixins.py +5 -5
  40. lino/sphinxcontrib/actordoc.py +1 -1
  41. lino/sphinxcontrib/logo/static/linodocs.css +1 -8
  42. lino/utils/choosers.py +1 -1
  43. lino/utils/report.py +4 -11
  44. {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/METADATA +1 -1
  45. {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/RECORD +48 -49
  46. lino/core/tablerequest.py +0 -758
  47. {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/WHEEL +0 -0
  48. {lino-24.9.4.dist-info → lino-24.10.1.dist-info}/licenses/AUTHORS.rst +0 -0
  49. {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, TableRequest
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(rr, name):
133
- if isinstance(rr, TableRequest):
134
- return rr.actor.master_key == name
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(Table, cls).init_layouts()
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(Table, self).get_chooser_for_field(fieldname)
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(Table, self).get_detail_sets():
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
- # try:
340
- # return qs.get(pk=pk)
341
- # # return self.get_queryset(ar).get(pk=pk)
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
- # except self.model.DoesNotExist:
345
- # # import sqlparse
346
- # # sql = str(qs.query).replace('"', '')
347
- # # sql = sqlparse.format(sql, reindent=True, keyword_case='upper')
348
- # # raise Exception("20240324 {}, {}".format(ar.param_values, sql))
349
- # return None
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(Table, self).class_init()
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(Table, self).do_setup()
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(Table, cls).make_disabled_fields(obj, ar)
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
- # 20200425
638
- spv = dict()
639
- for k in self.simple_parameters:
640
- v = getattr(ar.param_values, k)
641
- # if "room" in k:
642
- # print("20200423", k, v, self.simple_parameters, ar.param_values)
643
- if v == constants.CHOICES_BLANK_FILTER_VALUE:
644
- spv[k + "__isnull"] = True
645
- elif v == constants.CHOICES_NOT_BLANK_FILTER_VALUE:
646
- spv[k + "__isnull"] = False
647
- elif v is not None:
648
- spv[k] = v
649
- # print("20240506 {} = {}".format(k, v))
650
- ar.known_values[k] = v # make it an obvious field
651
-
652
- qs = self.model.add_param_filter(qs, **spv)
653
- # qs = self.model.add_param_filter(qs, **ar.param_values)
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
- kw["virtualField"] = True
859
- kw["noHeaderDecore"] = True
860
- kw["noEditorHeader"] = True
861
- kw["alwaysEditable"] = True
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 represent a
2315
- table or a slave 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, "list_layout"):
2346
+ if not hasattr(self.rh, "grid_layout"):
2347
2347
  raise Exception(
2348
- "Handle for {0} (model {1}) has no list_layout".format(
2348
+ "Handle for {0} (model {1}) has no grid_layout".format(
2349
2349
  rpt, rpt.model
2350
2350
  )
2351
2351
  )
2352
- columns = self.rh.list_layout.main.columns
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 dms:
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 dms:
2438
+ if constants.DISPLAY_MODE_LIST in rpt.extra_display_modes:
2441
2439
  slaves["list"] = get_list_element(layout_handle, rpt, name, **kw)
2442
- # if constants.DISPLAY_MODE_HTML in dms:
2443
- # slaves["html"] = get_htmlbox_element(layout_handle, rpt, name, **kw)
2444
- # if constants.DISPLAY_MODE_SUMMARY in dms:
2445
- # slaves["summary"] = get_summary_element(layout_handle, rpt, name, **kw)
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
- # DetailWindow, then it will be rendered as a panel that
2850
- # displays a "summary" of that table. The panel will have
2851
- # a tool button to "open that table in its own
2852
- # window". The format of that summary is defined by the
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.display_mode) > 1
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.DISPLAY_MODE_TABLE,
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="story")
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
- ll = layouts.ColumnsLayout(
880
+ gl = layouts.ColumnsLayout(
881
881
  h.actor.get_column_names(ar), h.actor, hidden_elements=he
882
882
  )
883
- h.list_layout = ll.get_layout_handle()
883
+ h.grid_layout = gl.get_layout_handle()
884
884
  else:
885
- h.list_layout = None
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 .tablerequest import TableRequest, sliced_data_iterator
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, TableRequest):
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
- # yield E.p(display_mode)
282
- if not nosummary:
283
- if display_mode == constants.DISPLAY_MODE_SUMMARY:
284
- yield ar.actor.get_table_summary(ar.master_instance, ar)
285
- return
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.dbtables.TableRequest>`: a button :guilabel:`[New]`
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 TableRequest
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
- # 20200501 elems.append(self.show_story(ar, item.actor.get_story(None, ar), **kwargs))
651
- elems += [tostring(e)
652
- for e in self.show_story(
653
- ar, item.actor.get_story(None, ar), **kwargs)]
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
- # display_mode = [dmi[1] for dmi in ar.actor.display_mode if dmi[0] is None][0]
823
- # if ar.actor.master is not None and not nosummary:
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 not nosummary:
826
- if display_mode == constants.DISPLAY_MODE_SUMMARY:
827
- s = to_rst(
828
- ar.actor.get_table_summary(ar.master_instance, ar),
829
- stripped=stripped,
830
- )
831
- if stripped:
832
- s = s.strip()
833
- yield s
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 TableRequest
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
- self.show_story(ar, item.actor.get_story(None, ar), **kwargs)
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):