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/__init__.py CHANGED
@@ -26,11 +26,7 @@ defines no models, some template files, a series of :term:`django-admin commands
26
26
 
27
27
  """
28
28
 
29
- __version__ = '24.9.4'
30
-
31
- # from __future__ import unicode_literals
32
- # from __future__ import absolute_import
33
- # from builtins import str
29
+ __version__ = '24.10.1'
34
30
 
35
31
  # import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
36
32
 
lino/api/doctest.py CHANGED
@@ -7,9 +7,9 @@ A selection of names to be used in tested documents.
7
7
 
8
8
  import six # TODO: remove here and then run all doctests
9
9
  import logging
10
- import django
11
10
  import sqlparse
12
-
11
+ from urllib.parse import urlencode
12
+ import django
13
13
  django.setup()
14
14
  from lino.core.constants import *
15
15
  from lino.api.shell import *
@@ -63,12 +63,18 @@ HttpQuery = collections.namedtuple(
63
63
 
64
64
  def get_json_dict(username, uri, an="detail", **kwargs):
65
65
  url = "/api/{0}?fmt=json&an={1}".format(uri, an)
66
- for k, v in kwargs.items():
67
- url += "&{}={}".format(k, v)
66
+ if kwargs:
67
+ url += "&" + urlencode(kwargs, True)
68
+ # for k, v in kwargs.items():
69
+ # url += "&{}={}".format(k, v)
68
70
  test_client.force_login(rt.login(username).user)
69
71
  res = test_client.get(url, REMOTE_USER=username)
70
72
  assert res.status_code == 200
71
- return json.loads(res.content.decode())
73
+ s = res.content.decode()
74
+ try:
75
+ return json.loads(s)
76
+ except Exception as e:
77
+ raise Exception(f"GET {url} got non-JSON response:\n{s}") from None
72
78
 
73
79
 
74
80
  def get_json_soup(username, uri, fieldname, **kwargs):
@@ -314,7 +320,7 @@ def get_fields(model, fieldnames=None, columns=None):
314
320
  get_field = model.get_data_elem
315
321
  if fieldnames is None:
316
322
  fieldnames = model.column_names
317
- # get_handle().list_layout.main.columns
323
+ # get_handle().grid_layout.main.columns
318
324
  else:
319
325
  get_field = model.parameters.get
320
326
  if fieldnames is None:
@@ -773,3 +779,20 @@ def show_change_watchers():
773
779
  [full_model_name(m), ws.master_key, " ".join(sorted(ws.ignored_fields))]
774
780
  )
775
781
  print(table(headers, rows, max_width=40))
782
+
783
+ def show_display_modes():
784
+ """
785
+ Show the availble display modes per actor.
786
+ """
787
+ dml = sorted(constants.DISPLAY_MODES - constants.BASIC_DISPLAY_MODES)
788
+ headers = ["actor"]
789
+ headers += dml
790
+ rows = []
791
+ for a in sorted(actors.actors_list, key=str):
792
+ if not a.is_abstract():
793
+ rows.append(
794
+ [str(a)] + [
795
+ ("x" if dm in a.extra_display_modes else "")
796
+ for dm in dml]
797
+ )
798
+ print(table(headers, rows))
lino/core/__init__.py CHANGED
@@ -39,7 +39,6 @@ For some modules the documentation has already been migrated to prosa:
39
39
  signals
40
40
  store
41
41
  tables
42
- tablerequest
43
42
  urls
44
43
  userprefs
45
44
  user_types
lino/core/actions.py CHANGED
@@ -33,7 +33,7 @@ from .utils import resolve_model
33
33
  from .utils import navinfo
34
34
  from .utils import Parametrizable
35
35
  from .utils import traverse_ddh_fklist
36
- from .requests import InstanceAction
36
+ from .utils import InstanceAction
37
37
 
38
38
 
39
39
  def discover_choosers():
@@ -85,7 +85,10 @@ def resolve_layout(cls, k, spec, layout_class, **options):
85
85
  def install_layout(cls, k, layout_class, **options):
86
86
  """
87
87
  - `cls` is the actor (a class object)
88
- - `k` is one of 'detail_layout', 'insert_layout', 'params_layout', 'card_layout', 'list_layout'
88
+
89
+ - `k` is one of 'grid_layout', 'detail_layout', 'insert_layout',
90
+ 'params_layout', 'card_layout', 'list_layout'
91
+
89
92
  - `layout_class`
90
93
 
91
94
  """
@@ -437,6 +440,8 @@ class Action(Parametrizable, Permittable):
437
440
  On actions that opens_a_window this must be a unique one-letter
438
441
  string expressing the window type.
439
442
 
443
+ See `constants.WINDOW_TYPES`.
444
+
440
445
  Allowed values are:
441
446
 
442
447
  - None : opens_a_window is False
@@ -486,6 +491,12 @@ class Action(Parametrizable, Permittable):
486
491
 
487
492
  register_params(self)
488
493
 
494
+ if self.callable_from is not None:
495
+ for c in self.callable_from:
496
+ if not c in constants.WINDOW_TYPES:
497
+ raise Exception(f"Invalid window_type spec {c} in {self}")
498
+
499
+
489
500
  def __get__(self, instance, owner):
490
501
  """
491
502
  When a model has an action "foo", then getting an attribute
@@ -785,7 +796,7 @@ class ShowTable(TableAction):
785
796
  use_param_panel = True
786
797
  show_in_workflow = False
787
798
  opens_a_window = True
788
- window_type = "t"
799
+ window_type = constants.WINDOW_TYPE_TABLE
789
800
  action_name = "grid"
790
801
  select_rows = False
791
802
  callable_from = None
@@ -809,7 +820,7 @@ class ShowDetail(Action):
809
820
  icon_name = "application_form"
810
821
  ui5_icon_name = "sap-icon://detail-view"
811
822
  opens_a_window = True
812
- window_type = "d"
823
+ window_type = constants.WINDOW_TYPE_DETAIL
813
824
  show_in_workflow = False
814
825
  save_action_name = "submit_detail"
815
826
  callable_from = "t"
@@ -893,7 +904,7 @@ class ShowInsert(TableAction):
893
904
  show_in_workflow = False
894
905
  show_in_side_toolbar = True
895
906
  opens_a_window = True
896
- window_type = "i"
907
+ window_type = constants.WINDOW_TYPE_INSERT
897
908
  hide_navigator = True # 20210509
898
909
  hide_top_toolbar = True # 20210509
899
910
  sort_index = 10
@@ -1342,11 +1353,7 @@ class DeleteSelected(MultipleRowAction):
1342
1353
  sort_index = 30
1343
1354
  readonly = False
1344
1355
  show_in_workflow = False
1345
- # required_roles = set([SiteUser])
1346
- # ~ callable_from = (ShowTable,ShowDetail)
1347
- # ~ needs_selection = True
1348
1356
  label = _("Delete")
1349
- # ~ url_action_name = 'delete'
1350
1357
  hotkey = keyboard.DELETE # (ctrl=True)
1351
1358
 
1352
1359
  # ~ client_side = True
lino/core/actors.py CHANGED
@@ -27,10 +27,10 @@ from lino.utils import MissingRow
27
27
  from lino.core import fields
28
28
  from lino.core import actions
29
29
  from lino.core import layouts
30
- from lino.core.requests import ActionRequest
30
+ from lino.core import constants
31
31
  from lino.core.boundaction import BoundAction
32
32
  from lino.core.exceptions import ChangedAPI
33
- from lino.core.constants import _handle_attr_name, CHOICES_BLANK_FILTER_VALUE
33
+ from lino.core.constants import _handle_attr_name
34
34
  from lino.core.permissions import add_requirements, Permittable
35
35
  from lino.core.utils import resolve_model
36
36
  from lino.core.utils import error2str
@@ -162,22 +162,12 @@ class ActorMetaClass(type):
162
162
 
163
163
  cls = super().__new__(meta, classname, bases, classDict)
164
164
 
165
- # ~ if not classDict.has_key('label'):
166
- # ~ cls.label = ClassProperty(cls.get_actor_label)
167
- # ~ meta.label = property(cls.get_actor_label.im_func) # 20130906
168
- # ~ if not classDict.has_key('known_values'):
169
- # ~ cls.known_values = ClassProperty(cls.get_known_values)
170
- # ~ meta.known_values = property(cls.get_known_values.im_func) # 20130906
171
- """
172
- On 20110822 I thought "A Table always gets the app_label of its model,
173
- you cannot set this yourself in a subclass
174
- because otherwise it gets complex when inheriting reports from other
175
- app_labels."
176
- On 20110912 I cancelled change 20110822 because PersonsByOffer
177
- should clearly get app_label 'jobs' and not 'contacts'.
178
-
179
- """
180
-
165
+ # On 20110822 I thought "A Table always gets the app_label of its model,
166
+ # you cannot set this yourself in a subclass
167
+ # because otherwise it gets complex when inheriting reports from other
168
+ # app_labels."
169
+ # On 20110912 I cancelled change 20110822 because PersonsByOffer
170
+ # should clearly get app_label 'jobs' and not 'contacts'.
181
171
  if classDict.get("app_label", None) is None:
182
172
  # Figure out the app_label by looking one level up.
183
173
  # For 'django.contrib.sites.models', this would be 'sites'.
@@ -291,7 +281,17 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
291
281
  # """
292
282
 
293
283
  only_fields = None
294
- display_mode = None
284
+
285
+ default_display_modes = None
286
+
287
+ # extra_display_modes = set()
288
+ # extra_display_modes = {constants.DISPLAY_MODE_SUMMARY}
289
+ extra_display_modes = {constants.DISPLAY_MODE_HTML}
290
+ """
291
+ A set of additional display modes to make available when rendering this table.
292
+
293
+ See :ref:`dg.dd.table.extra_display_modes`.
294
+ """
295
295
 
296
296
  app_label = None
297
297
  """
@@ -428,6 +428,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
428
428
  default_action = None
429
429
  actor_id = None
430
430
 
431
+ grid_layout = None
431
432
  detail_layout = None
432
433
  insert_layout = None
433
434
  card_layout = None
@@ -730,8 +731,12 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
730
731
 
731
732
  if hasattr(cls, "required"):
732
733
  raise ChangedAPI(
733
- "{0} must convert `required` to `required_roles`".format(cls)
734
+ f"{cls} must convert `required` to `required_roles`"
734
735
  )
736
+ if hasattr(cls, "display_mode"):
737
+ # cls.default_display_modes = {k:v for k, v in cls.display_mode}
738
+ # logger.info(f"{cls} uses deprecated `display_mode`, please convert to `default_display_modes`.")
739
+ raise ChangedAPI(f"{cls} must convert `display_mode` to `default_display_modes`")
735
740
 
736
741
  master = getattr(cls, "master", None)
737
742
  if isinstance(master, str):
@@ -760,6 +765,45 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
760
765
  cls.virtual_fields["detail_link"] = de
761
766
  # cls.add_virtual_field('detail_link', de)
762
767
 
768
+ if cls.abstract:
769
+ return
770
+
771
+ edm = set() # extra display modes to add automatically
772
+ if cls.default_display_modes is not None:
773
+ for v in cls.default_display_modes.values():
774
+ if v not in constants.DISPLAY_MODES:
775
+ raise Exception(f"Invalid display mode {v} in {cls}")
776
+ if v not in constants.BASIC_DISPLAY_MODES:
777
+ # be sure to have our copy the extra_display_modes set
778
+ # if str(cls) == "comments.Comments":
779
+ # print(f"20240929 extra_display_modes is {cls.extra_display_modes}, we add {v}")
780
+ # cls.extra_display_modes = cls.extra_display_modes | {v}
781
+ edm.add(v)
782
+
783
+ if cls.card_layout is not None:
784
+ edm.add(constants.DISPLAY_MODE_CARDS)
785
+ if 'row_as_paragraph' in cls.__dict__:
786
+ edm.add(constants.DISPLAY_MODE_LIST)
787
+ # if 'row_as_page' in cls.__dict__:
788
+ # edm.add(constants.DISPLAY_MODE_STORY)
789
+ if model is not None:
790
+ if model.extra_display_modes is not None:
791
+ for v in model.extra_display_modes:
792
+ if v not in constants.DISPLAY_MODES:
793
+ raise Exception(f"Invalid display mode {v} in {model}.extra_display_modes")
794
+ edm |= model.extra_display_modes
795
+ if 'as_paragraph' in model.__dict__:
796
+ edm.add(constants.DISPLAY_MODE_LIST)
797
+ if 'as_page' in model.__dict__:
798
+ edm.add(constants.DISPLAY_MODE_STORY)
799
+ # no need to automatically add summary because it's in default_display_modes of every table
800
+ # if 'as_summary_item' in model.__dict__:
801
+ # edm.add(constants.DISPLAY_MODE_SUMMARY)
802
+ if len(edm) > 0:
803
+ # if str(cls) == "comments.Comments":
804
+ # print(f"20240929 {cls} extra_display_modes add {edm}")
805
+ cls.extra_display_modes = cls.extra_display_modes | edm
806
+
763
807
  @classmethod
764
808
  def init_layouts(cls):
765
809
  # 20200430 this was previously part of class_init, but is now called in
@@ -1238,7 +1282,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1238
1282
  yield t
1239
1283
  for k in self.simple_parameters:
1240
1284
  v = getattr(ar.param_values, k)
1241
- if v and v != CHOICES_BLANK_FILTER_VALUE:
1285
+ if v and v != constants.CHOICES_BLANK_FILTER_VALUE:
1242
1286
  if v is True:
1243
1287
  # For BooleanField no need to add "True" in the title
1244
1288
  yield str(self.parameters[k].verbose_name)
@@ -1605,10 +1649,10 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1605
1649
  return wl.get_layout_handle()
1606
1650
 
1607
1651
  @classmethod
1608
- def get_list_layout(cls, *args):
1652
+ def get_grid_layout(cls, *args):
1609
1653
  assert cls.default_action is not None
1610
1654
  ah = cls.get_handle()
1611
- return ah.get_list_layout()
1655
+ return ah.get_grid_layout()
1612
1656
 
1613
1657
  @classmethod
1614
1658
  def get_detail_elems(cls):
@@ -1739,6 +1783,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1739
1783
  Return an action request on this actor.
1740
1784
  """
1741
1785
  kw.update(actor=self)
1786
+ from lino.core.requests import ActionRequest
1742
1787
  return ActionRequest(*args, **kw)
1743
1788
 
1744
1789
  @classmethod
@@ -1788,11 +1833,16 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1788
1833
  # welfare/docs/specs/weleup/weleup1r.rst
1789
1834
  # kwargs.update(request=ar.request)
1790
1835
  kwargs.update(parent=ar)
1791
-
1792
- ar = cls.request(master, **kwargs)
1793
- ar.renderer = settings.SITE.kernel.default_renderer
1794
- el = ar.table2xhtml()
1795
- toolbar = ar.plain_toolbar_buttons()
1836
+ kwargs.update(renderer=settings.SITE.kernel.default_renderer)
1837
+ try:
1838
+ ar = cls.request(master_instance=master, **kwargs)
1839
+ el = ar.table2xhtml()
1840
+ toolbar = ar.plain_toolbar_buttons()
1841
+ except Exception as e:
1842
+ msg = f"20241004 Error in {repr(ar)}: {e}"
1843
+ raise Exception(msg) from e
1844
+ logger.warning(msg)
1845
+ return msg
1796
1846
  if len(toolbar):
1797
1847
  el = E.div(el, E.p(*toolbar))
1798
1848
  return el
@@ -1831,6 +1881,25 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1831
1881
  # assert_safe(html_text) # temporary 20240506
1832
1882
  return format_html(DIVTPL, html_text)
1833
1883
 
1884
+ @classmethod
1885
+ def get_table_story(cls, obj, ar):
1886
+ sar = cls.request(parent=ar, master_instance=obj, is_on_main_actor=False)
1887
+ html = mark_safe("")
1888
+ for i, obj in enumerate(sar.data_iterator):
1889
+ if i == cls.preview_limit:
1890
+ break
1891
+ s = obj.as_story_item(sar)
1892
+ # assert_safe(s) # temporary 20240506
1893
+ html += s
1894
+ if cls.insert_action is not None:
1895
+ if not cls.editable:
1896
+ return html
1897
+ ir = cls.insert_action.request_from(sar)
1898
+ if ir.get_permission():
1899
+ html = tostring(ir.ar2button()) + html
1900
+ # assert_safe(html) # temporary 20240506
1901
+ return html
1902
+
1834
1903
  @classmethod
1835
1904
  def get_table_summary(cls, obj, ar):
1836
1905
  """
@@ -1892,7 +1961,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1892
1961
  if ar is None:
1893
1962
  return str(self)
1894
1963
  # cols = ar.actor.get_detail_layout().main
1895
- cols = cls.get_list_layout().main.columns
1964
+ cols = cls.get_grid_layout().main.columns
1896
1965
  cols = [c for c in cols if not c.value.get("hidden")]
1897
1966
  if fmt is None:
1898
1967
 
@@ -1914,7 +1983,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
1914
1983
  values = [v for v in values if v is not None]
1915
1984
  s = ", ".join(values)
1916
1985
  # s = str(ar.actor)
1917
- # print("20231218", s) # self, ar.actor.get_list_layout().main.columns)
1986
+ # print("20231218", s) # self, ar.actor.get_grid_layout().main.columns)
1918
1987
  return s
1919
1988
 
1920
1989
  @classmethod
lino/core/choicelists.py CHANGED
@@ -368,28 +368,43 @@ class ChoiceList(with_metaclass(ChoiceListMeta, tables.AbstractTable)):
368
368
  """A string with the name of a choice to be used as default value for
369
369
  fields using this list.
370
370
 
371
+ Usage example in :mod:`lino_xl.lib.clients.models`::
372
+
373
+ class ClientStates(dd.Workflow):
374
+ required_roles = dd.login_required(ContactsStaff)
375
+ verbose_name_plural = _("Client states")
376
+ default_value = 'newcomer'
377
+
378
+ add = ClientStates.add_item
379
+ add('10', _("Newcomer"), 'newcomer')
380
+ add('20', _("Refused"), 'refused')
381
+ add('30', _("Coached"), 'coached')
382
+ add('50', _("Former"), 'former')
383
+
384
+ And :mod:`lino_avant.lib.avanti.models` overrides it::
385
+
386
+ from lino_xl.lib.clients.choicelists import ClientStates
387
+ ClientStates.default_value = 'coached'
388
+
371
389
  Note that this specifies the *default* default value for *all*
372
390
  :class:`ChoiceListField <lino.core.choicelists.ChoiceListField>`
373
391
  of this choicelist, including parameter fields.
374
392
 
393
+ The disadvantage is that when somebody *does not* want your default value,
394
+ then they must explicitly specify `default=''` when defining a field on your
395
+ choicelist.
396
+
375
397
  You can remove that "default default value" for all tables by
376
398
  specifying `default=''`. There are two places where you can
377
399
  specify this: (a) on the parameter field itself (which then
378
400
  applies to all subtables) or (b) just on one table. For example
379
401
  (excerpt from :mod:`lino_avanti.lib.avanti`)::
380
402
 
381
- from lino_xl.lib.clients.choicelists import ClientStates
382
- ClientStates.default_value = 'coached'
383
-
384
403
  parameters = ObservedDateRange(
385
404
  ...
386
405
  client_state=ClientStates.field(blank=True, default=''))
387
406
 
388
- Note that the default values of parameter fields of a table that
389
- is used as the *models default table* will apply for the choices
390
- of pointers to that model. Concrete use case is the choicelist of
391
- `cal.Guest.partner` in :ref:`avanti`, which should show only
392
- coached clients. So instead of above code we actually now do::
407
+ Example for (b)::
393
408
 
394
409
  class MyClients(My, Clients):
395
410
  @classmethod
@@ -398,9 +413,11 @@ class ChoiceList(with_metaclass(ChoiceListMeta, tables.AbstractTable)):
398
413
  kw.update(client_state='')
399
414
  return kw
400
415
 
401
- The disadvantage is that when somebody *does not* want your default value,
402
- then they must explicitly specify `default=''` when defining a field on your
403
- choicelist.
416
+ Note that the default values of parameter fields of a table that
417
+ is used as the *model's default table* will apply for the choices
418
+ of pointers to that model. Concrete use case is the choicelist of
419
+ `cal.Guest.partner` in :ref:`avanti`, which we want to show only
420
+ coached clients.
404
421
 
405
422
  """
406
423
 
lino/core/constants.py CHANGED
@@ -47,22 +47,38 @@ URL_PARAM_WINDOW_TYPE = "wt"
47
47
 
48
48
  WINDOW_TYPE_TABLE = "t"
49
49
  WINDOW_TYPE_DETAIL = "d"
50
- WINDOW_TYPE_CARDS = "c"
51
- WINDOW_TYPE_GALLERIA = "g"
52
50
  WINDOW_TYPE_INSERT = "i"
53
51
  WINDOW_TYPE_PARAMS = "p"
54
52
 
53
+ WINDOW_TYPES = {
54
+ WINDOW_TYPE_TABLE, WINDOW_TYPE_DETAIL, WINDOW_TYPE_INSERT,
55
+ WINDOW_TYPE_PARAMS
56
+ }
57
+
55
58
  URL_PARAM_DISPLAY_MODE = "dm"
56
59
 
57
- DISPLAY_MODE_TABLE = "grid" # deprecated
58
60
  DISPLAY_MODE_GRID = "grid"
59
61
  DISPLAY_MODE_DETAIL = "detail"
62
+ DISPLAY_MODE_HTML = "html"
60
63
  DISPLAY_MODE_SUMMARY = "summary"
61
64
  DISPLAY_MODE_LIST = "list"
62
65
  DISPLAY_MODE_CARDS = "cards"
63
66
  DISPLAY_MODE_GALLERY = "gallery"
64
67
  DISPLAY_MODE_STORY = "story"
65
- DISPLAY_MODE_HTML = "html"
68
+
69
+ DISPLAY_MODES = {
70
+ DISPLAY_MODE_GRID,
71
+ DISPLAY_MODE_DETAIL,
72
+ DISPLAY_MODE_HTML,
73
+ DISPLAY_MODE_SUMMARY,
74
+ DISPLAY_MODE_LIST,
75
+ DISPLAY_MODE_CARDS,
76
+ DISPLAY_MODE_GALLERY,
77
+ DISPLAY_MODE_STORY}
78
+
79
+ BASIC_DISPLAY_MODES = {
80
+ DISPLAY_MODE_GRID,
81
+ DISPLAY_MODE_DETAIL}
66
82
 
67
83
  # ~ URL_PARAM_EUSER = 'euser'
68
84
  # ~ URL_PARAM_EUSER = 'su'
lino/core/dashboard.py CHANGED
@@ -7,9 +7,13 @@
7
7
 
8
8
  from lino.api import _
9
9
  from lino.core.permissions import Permittable
10
+ from lino.core.requests import ActionRequest
11
+ from lino.core.tables import AbstractTable
12
+ # from lino.core.actions import ShowTable
10
13
  from lino.utils.html import E, tostring, assert_safe
11
14
  from django.utils.html import mark_safe
12
15
 
16
+
13
17
  class DashboardItem(Permittable):
14
18
  """Base class for all dashboard items.
15
19
 
@@ -51,9 +55,6 @@ class DashboardItem(Permittable):
51
55
  This is a helper function for shared use by :class:`ActorItem`
52
56
  and :class:`RequestItem`.
53
57
  """
54
- from lino.core.tables import TableRequest
55
- from lino.core.requests import ActionRequest
56
-
57
58
  assert ar.user is sar.user
58
59
  # T = sar.actor
59
60
  # print("20210112 render_request()", sar.actor, sar)
@@ -72,22 +73,22 @@ class DashboardItem(Permittable):
72
73
  yield tostring(E.h2(str(sar.actor.get_title_base(sar)), " ", *elems))
73
74
 
74
75
  assert sar.renderer is not None
75
- if isinstance(sar, TableRequest):
76
+ if isinstance(sar, ActionRequest):
76
77
  # TODO 20220930 until now, dashboard was always acting as if
77
- # display_mode was DISPLAY_MODE_TABLE
78
- # if sar.actor.display_mode == constants.DISPLAY_MODE_TABLE
79
-
80
- for e in sar.renderer.table2story(sar, **kwargs):
81
- # assert_safe(tostring(e))
82
- yield tostring(e)
83
- elif isinstance(sar, ActionRequest):
84
- # example : courses.StatusReport in dashboard
85
- yield sar.renderer.show_story(
86
- ar, sar.actor.get_story(None, ar), **kwargs)
87
- # for e in sar.renderer.show_story(
88
- # ar, sar.actor.get_story(None, ar), **kwargs):
89
- # # assert_safe(tostring(e))
90
- # yield tostring(e)
78
+ # display_mode was DISPLAY_MODE_GRID
79
+ if issubclass(sar.actor, AbstractTable):
80
+ # if isinstance(sar.bound_action.action, ShowTable):
81
+ for e in sar.renderer.table2story(sar, **kwargs):
82
+ # assert_safe(tostring(e))
83
+ yield tostring(e)
84
+ else:
85
+ # example : courses.StatusReport in dashboard
86
+ yield sar.renderer.show_story(
87
+ ar, sar.actor.get_story(None, ar), **kwargs)
88
+ # for e in sar.renderer.show_story(
89
+ # ar, sar.actor.get_story(None, ar), **kwargs):
90
+ # # assert_safe(tostring(e))
91
+ # yield tostring(e)
91
92
  else:
92
93
  raise Exception("20240908 Cannot render {}".format(sar))
93
94
  yield "Cannot render {}".format(sar)