lino 25.8.3__py3-none-any.whl → 25.9.0__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 (61) hide show
  1. lino/__init__.py +1 -1
  2. lino/api/dd.py +0 -1
  3. lino/core/__init__.py +0 -1
  4. lino/core/actions.py +1 -1
  5. lino/core/actors.py +8 -0
  6. lino/core/elems.py +1 -1
  7. lino/core/fields.py +4 -1
  8. lino/core/model.py +2 -11
  9. lino/core/requests.py +8 -7
  10. lino/core/site.py +0 -79
  11. lino/core/user_types.py +1 -10
  12. lino/help_texts.py +1 -5
  13. lino/management/commands/initdb.py +0 -3
  14. lino/modlib/__init__.py +0 -1
  15. lino/modlib/bootstrap5/README.txt +1 -1
  16. lino/modlib/bootstrap5/__init__.py +34 -38
  17. lino/modlib/bootstrap5/config/bootstrap5/base.html +4 -0
  18. lino/modlib/bootstrap5/models.py +23 -23
  19. lino/modlib/bootstrap5/views.py +2 -107
  20. lino/modlib/checkdata/choicelists.py +1 -1
  21. lino/modlib/comments/fixtures/demo2.py +1 -0
  22. lino/modlib/comments/ui.py +7 -7
  23. lino/modlib/extjs/__init__.py +2 -4
  24. lino/modlib/extjs/config/extjs/index.html +1 -1
  25. lino/modlib/extjs/ext_renderer.py +1 -7
  26. lino/modlib/extjs/views.py +2 -0
  27. lino/modlib/help/models.py +1 -12
  28. lino/modlib/linod/mixins.py +3 -2
  29. lino/modlib/memo/__init__.py +10 -9
  30. lino/modlib/memo/mixins.py +38 -21
  31. lino/modlib/memo/models.py +10 -7
  32. lino/modlib/memo/parser.py +3 -1
  33. lino/modlib/notify/models.py +6 -9
  34. lino/modlib/publisher/__init__.py +12 -7
  35. lino/modlib/publisher/choicelists.py +9 -64
  36. lino/modlib/publisher/config/publisher/page.pub.html +73 -7
  37. lino/modlib/publisher/fixtures/std.py +14 -1
  38. lino/modlib/publisher/mixins.py +41 -12
  39. lino/modlib/publisher/models.py +74 -75
  40. lino/modlib/publisher/renderer.py +28 -12
  41. lino/modlib/publisher/ui.py +35 -35
  42. lino/modlib/publisher/views.py +59 -24
  43. lino/modlib/system/models.py +3 -2
  44. lino/modlib/uploads/__init__.py +1 -0
  45. lino/modlib/uploads/mixins.py +2 -2
  46. lino/modlib/uploads/models.py +55 -21
  47. lino/modlib/uploads/ui.py +1 -0
  48. lino/modlib/uploads/utils.py +2 -2
  49. lino/modlib/users/__init__.py +2 -3
  50. lino/modlib/users/actions.py +12 -17
  51. lino/modlib/users/models.py +37 -36
  52. lino/modlib/weasyprint/choicelists.py +6 -0
  53. lino/utils/diag.py +5 -3
  54. lino/utils/html.py +103 -0
  55. lino/utils/mldbc/mixins.py +2 -2
  56. lino/utils/soup.py +16 -8
  57. {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/METADATA +1 -1
  58. {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/RECORD +61 -61
  59. {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/WHEEL +0 -0
  60. {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/licenses/AUTHORS.rst +0 -0
  61. {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/licenses/COPYING +0 -0
lino/__init__.py CHANGED
@@ -31,7 +31,7 @@ from django import VERSION
31
31
  from django.apps import AppConfig
32
32
  from django.conf import settings
33
33
  import warnings
34
- __version__ = '25.8.3'
34
+ __version__ = '25.9.0'
35
35
 
36
36
  # import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
37
37
 
lino/api/dd.py CHANGED
@@ -189,7 +189,6 @@ resolve_plugin = settings.SITE.resolve_plugin
189
189
  get_plugin_setting = settings.SITE.get_plugin_setting
190
190
  add_welcome_handler = settings.SITE.add_welcome_handler
191
191
  build_media_url = settings.SITE.build_media_url
192
- build_site_cache_url = settings.SITE.build_site_cache_url
193
192
  build_static_url = settings.SITE.build_static_url
194
193
  get_default_language = settings.SITE.get_default_language
195
194
  get_language_info = settings.SITE.get_language_info
lino/core/__init__.py CHANGED
@@ -39,7 +39,6 @@ For some modules the documentation has already been migrated to prosa:
39
39
  tables
40
40
  urls
41
41
  userprefs
42
- user_types
43
42
  utils
44
43
  views
45
44
  workflows
lino/core/actions.py CHANGED
@@ -595,7 +595,7 @@ class SubmitDetail(SaveGridCell):
595
595
  ar.goto_instance(elem)
596
596
  else:
597
597
  if len(ar.selected_rows) == 1:
598
- ar.set_response(data_record=ar.elem2rec_detailed(elem))
598
+ ar.success(data_record=ar.elem2rec_detailed(elem))
599
599
 
600
600
 
601
601
  class CreateRow(Action):
lino/core/actors.py CHANGED
@@ -1715,6 +1715,14 @@ class Actor(Parametrizable, Permittable, metaclass=ActorMetaClass):
1715
1715
  kw = self.model.param_defaults(ar, **kw)
1716
1716
  return kw
1717
1717
 
1718
+ # @classmethod
1719
+ # def get_parent_links(cls, ar):
1720
+ # if cls.model is not None:
1721
+ # for pl in cls.model.get_parent_links(ar):
1722
+ # yield pl
1723
+ # # if (mi := ar.master_instance) is not None:
1724
+ # # yield ar.obj2htmls(mi, str(mi))
1725
+
1718
1726
  @classmethod
1719
1727
  def request(cls, *args, **kwargs):
1720
1728
  """
lino/core/elems.py CHANGED
@@ -37,7 +37,7 @@ from lino.core import actions
37
37
  from lino.core.utils import resolve_model
38
38
  from lino.core.gfks import GenericRelation, GenericRel
39
39
  from lino.core.permissions import Permittable
40
- from lino.modlib.bootstrap5.views import table2html
40
+ from lino.utils.html import table2html
41
41
 
42
42
  from lino.utils.jsgen import VisibleComponent
43
43
  from lino.utils.html import E, tostring, forcetext, html2text
lino/core/fields.py CHANGED
@@ -1265,7 +1265,7 @@ class ImportedFields(object):
1265
1265
  # ~ cls,cls._imported_fields))
1266
1266
 
1267
1267
 
1268
- class TableRow(object):
1268
+ class TableRow:
1269
1269
  """Base class for everything that can be used as a table row."""
1270
1270
 
1271
1271
  _lino_default_table = None
@@ -1420,6 +1420,9 @@ class TableRow(object):
1420
1420
  # raise Exception("20230425 {}".format(ar.actor))
1421
1421
  return a
1422
1422
 
1423
+ def get_parent_links(self, ar):
1424
+ return []
1425
+
1423
1426
  def get_choices_text(self, ar, actor, field):
1424
1427
  return self.as_str(ar)
1425
1428
  # return str(self)
lino/core/model.py CHANGED
@@ -44,7 +44,7 @@ from .tables import AbstractTable
44
44
 
45
45
  class Model(models.Model, fields.TableRow):
46
46
 
47
- class Meta(object):
47
+ class Meta:
48
48
  abstract = True
49
49
 
50
50
  allow_cascaded_delete = frozenset()
@@ -436,16 +436,6 @@ class Model(models.Model, fields.TableRow):
436
436
  new = old
437
437
  else:
438
438
  new = sanitize(old, **kwargs)
439
- # try:
440
- # new = bleach.clean(
441
- # new,
442
- # tags=settings.SITE.bleach_allowed_tags,
443
- # attributes=settings.SITE.bleach_allowed_attributes,
444
- # strip=True,
445
- # )
446
- # except TypeError as e:
447
- # logger.warning("Could not bleach %r : %s (%s)", old, e, self)
448
- # continue
449
439
  if old != new:
450
440
  logger.debug("Bleaching %s from %r to %r", f.name, old, new)
451
441
  yield f, old, new
@@ -1003,6 +993,7 @@ LINO_MODEL_ATTRIBS = (
1003
993
  "show_in_site_search",
1004
994
  "allow_merge_action",
1005
995
  "get_overview_elems",
996
+ "get_parent_links",
1006
997
  )
1007
998
 
1008
999
 
lino/core/requests.py CHANGED
@@ -1676,17 +1676,18 @@ class BaseRequest:
1676
1676
  return rec
1677
1677
 
1678
1678
  def get_breadcrumbs(self, elem=None):
1679
+ # print("20250910 get_breadcrumbs", self)
1679
1680
  list_title = self.get_title()
1680
- # TODO: make it clickable so that we can return from detail to list view
1681
- if elem is None or self.actor.default_record_id is not None:
1682
- return list_title
1683
- else:
1684
- # print("20190703", self.actor, self.actor.default_action)
1681
+ if self.actor.default_record_id is None:
1685
1682
  sar = self.spawn_request(actor=self.actor)
1686
1683
  list_title = tostring(sar.href_to_request(
1687
1684
  sar, list_title, icon_name=None))
1688
- # return list_title + " » " + self.get_detail_title(elem)
1689
- return format_html("{} » {}", list_title, self.get_detail_title(elem))
1685
+ if elem is not None:
1686
+ list_title = format_html(
1687
+ "{} » {}", list_title, self.get_detail_title(elem))
1688
+ for pl in elem.get_parent_links(self):
1689
+ list_title = format_html("{} » {}", pl, list_title)
1690
+ return list_title
1690
1691
 
1691
1692
  def form2obj_and_save(ar, data, elem, is_new):
1692
1693
  """
lino/core/site.py CHANGED
@@ -262,7 +262,6 @@ class Site(object):
262
262
  use_elasticsearch = False
263
263
  use_solr = False
264
264
  developer_site_cache = None
265
- never_build_site_cache = False
266
265
  keep_erroneous_cache_files = False
267
266
  use_java = True
268
267
  use_systemd = False
@@ -1131,48 +1130,8 @@ class Site(object):
1131
1130
  # sfd = tuple([x for x in sfd if x != root])
1132
1131
  # self.update_settings(STATICFILES_DIRS=sfd)
1133
1132
 
1134
- # if self.build_js_cache_on_startup or self.never_build_site_cache:
1135
- # sfd = list(self.django_settings.get('STATICFILES_DIRS', []))
1136
- # sfd.append(self.media_root)
1137
- # self.update_settings(STATICFILES_DIRS=sfd)
1138
-
1139
1133
  # print(20150331, self.django_settings['FIXTURE_DIRS'])
1140
1134
 
1141
- # def setup_cache_directory(self):
1142
- # stamp = self.site_dir / "lino_cache.txt"
1143
- # this = class2str(self.__class__)
1144
- # if stamp.exists():
1145
- # other = stamp.read_file()
1146
- # if other == this:
1147
- # ok = True
1148
- # else:
1149
- # ok = False
1150
- # for parent in self.__class__.__mro__:
1151
- # if other == class2str(parent):
1152
- # ok = True
1153
- # break
1154
- # if not ok:
1155
- # # Can happen e.g. when `python -m lino.hello` is
1156
- # # called. in certain conditions.
1157
- # msg = (
1158
- # "Cannot use {site_dir} for {this} "
1159
- # "because it is used for {other}. (Settings {settings})"
1160
- # )
1161
- # msg = msg.format(
1162
- # site_dir=self.site_dir,
1163
- # this=this,
1164
- # settings=self.django_settings.get("SETTINGS_MODULE"),
1165
- # other=other,
1166
- # )
1167
- # if True:
1168
- # raise Exception(msg)
1169
- # else:
1170
- # # print(msg)
1171
- # self.site_dir = None
1172
- # else:
1173
- # self.makedirs_if_missing(self.site_dir)
1174
- # stamp.write_file(this)
1175
-
1176
1135
  def set_user_model(self, spec):
1177
1136
  # if self.user_model is not None:
1178
1137
  # msg = "Site.user_model was already set!"
@@ -2022,44 +1981,12 @@ class Site(object):
2022
1981
  def build_site_cache(self, force=False, later=False, verbosity=1):
2023
1982
  from lino.modlib.users.utils import with_user_profile
2024
1983
  from lino.modlib.users.choicelists import UserTypes
2025
- # from django.utils import translation
2026
- # if not self.is_prepared:
2027
- # self.prepare_layouts()
2028
- # self.is_prepared = True
2029
- # settings_file = self.django_settings.get("__file__")
2030
- # Path(settings_file).touch()
2031
- # p = self.site_dir / "lino_version.txt"
2032
- # p.touch()
2033
1984
  self.kernel.touch_lino_version()
2034
1985
 
2035
1986
  if later:
2036
1987
  # print("20230823 later")
2037
1988
  return
2038
1989
 
2039
- if self.never_build_site_cache:
2040
- self.logger.debug(
2041
- "Not building site cache because `settings.SITE.never_build_site_cache` is True"
2042
- )
2043
- # print("20230823 never")
2044
- return
2045
-
2046
- # logger.info("20140401 build_site_cache started")
2047
- if False:
2048
- # 20240907 until now the Site class creates the media directory if
2049
- # it doesn't exist, but the initdb command removes it again. So the
2050
- # following code seems really useless:
2051
- if not self.media_root.is_dir():
2052
- self.media_root.mkdir()
2053
- # try:
2054
- # settings.SITE.media_root.mkdir()
2055
- # except Exception as e:
2056
- # logger.debug(
2057
- # "Not building site cache because 'mkdir %s' says %s.",
2058
- # settings.SITE.media_root, e)
2059
- # return
2060
-
2061
- self.makedirs_if_missing(self.media_root / "webdav")
2062
-
2063
1990
  if verbosity > 0:
2064
1991
  self.logger.info("Build site cache in %s.", self.media_root)
2065
1992
 
@@ -2220,12 +2147,6 @@ class Site(object):
2220
2147
  def build_static_url(self, *args, **kw):
2221
2148
  return buildurl(settings.STATIC_URL, *args, **kw)
2222
2149
 
2223
- def build_site_cache_url(self, *args, **kw):
2224
- assert str(self.media_root) == str(settings.MEDIA_ROOT)
2225
- # if str(self.media_root) != str(settings.MEDIA_ROOT):
2226
- # return self.build_static_url(*args, **kw)
2227
- return self.build_media_url(*args, **kw)
2228
-
2229
2150
  def welcome_html(self, ui=None):
2230
2151
  from django.utils.translation import gettext as _
2231
2152
 
lino/core/user_types.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2015-2018 Rumma & Ko Ltd
1
+ # Copyright 2015-2025 Rumma & Ko Ltd
2
2
  # License: GNU Affero General Public License v3 (see file COPYING for details)
3
3
  """
4
4
  Defines a set of user types "Anonymous", "User" and
@@ -10,17 +10,8 @@ This can be used directly as :attr:`user_types_module
10
10
 
11
11
  from django.utils.translation import gettext_lazy as _
12
12
  from lino.core.roles import UserRole, SiteAdmin, SiteUser
13
-
14
- # from lino.modlib.office.roles import OfficeUser, OfficeStaff
15
13
  from lino.modlib.users.choicelists import UserTypes
16
14
 
17
- # class SiteAdmin(SiteAdmin, OfficeStaff):
18
- # pass
19
- #
20
- # class SiteUser(SiteUser, OfficeUser):
21
- # pass
22
-
23
- UserTypes.clear()
24
15
  add = UserTypes.add_item
25
16
  add("000", _("Anonymous"), UserRole, name="anonymous", readonly=True)
26
17
  add("100", _("User"), SiteUser, name="user")
lino/help_texts.py CHANGED
@@ -103,10 +103,6 @@ help_texts = {
103
103
  'lino.mixins.sequenced.Hierarchical.whole_clan' : _("""Return a set of this instance and all children and grandchildren."""),
104
104
  'lino.mixins.sequenced.Hierarchical.whole_tree' : _("""Returns a tuple with two items (obj, children) representing the whole tree."""),
105
105
  'lino.modlib.about.Plugin' : _("""See /dev/plugins."""),
106
- 'lino.modlib.bootstrap5.renderer.Renderer' : _("""A HTML render that uses Bootstrap3."""),
107
- 'lino.modlib.bootstrap5.views.List' : _("""Render a list of records."""),
108
- 'lino.modlib.bootstrap5.views.Element' : _("""Render a single record."""),
109
- 'lino.modlib.bootstrap5.views.Index' : _("""Render the main page."""),
110
106
  'lino.modlib.checkdata.Plugin' : _("""The config descriptor for this plugin."""),
111
107
  'lino.modlib.checkdata.Plugin.on_plugins_loaded' : _("""Set responsible_user to "'robin' if this is a demo site (is_demo_site)."""),
112
108
  'lino.modlib.checkdata.roles.CheckdataUser' : _("""Can see checkdata messages."""),
@@ -216,6 +212,7 @@ help_texts = {
216
212
  'lino.utils.diag.Analyzer.show_window_fields' : _("""List all window actions and the form fields they contain."""),
217
213
  'lino.utils.diag.Analyzer.show_window_permissions' : _("""List all window actions and the user types that can see them."""),
218
214
  'lino.utils.diag.Analyzer.show_memo_commands' : _("""List the memo commands defined in this application."""),
215
+ 'lino.utils.diag.Analyzer.show_db_structure' : _("""Show a bullet list of all models and their fields."""),
219
216
  'lino.utils.diag.Analyzer.show_database_structure' : _("""Show a bullet list of all models and their fields."""),
220
217
  'lino.utils.diag.Analyzer.show_db_overview' : _("""Print a reStructredText-formatted “database overview” report. Used by test cases in tested documents."""),
221
218
  'lino.utils.diag.Analyzer.show_foreign_keys' : _("""Return a list that shows how database objects are being referred to by some other database object. This information is important (1) before deleting objects and (2) when merging them."""),
@@ -399,7 +396,6 @@ help_texts = {
399
396
  'lino.modlib.publisher.PublishableContent.publishing_state' : _("""Default value is ‘draft’"""),
400
397
  'lino.modlib.publisher.PublishableContent.filler' : _("""Pointer to PageFillers"""),
401
398
  'lino.modlib.publisher.PublishingStates' : _("""A choicelist with the possible states of a publisher page."""),
402
- 'lino.modlib.publisher.PageFillers' : _("""A choicelist with the page fillers that are available for this application."""),
403
399
  'lino.modlib.publisher.SpecialPages' : _("""A choicelist with the special pages available on this site."""),
404
400
  'lino.modlib.search.SiteSearch' : _("""A virtual table that searches in all database tables."""),
405
401
  'lino.modlib.search.ElasticSiteSearch' : _("""A virtual table used to search on this Lino site using ElasticSearch."""),
@@ -301,9 +301,6 @@ class Command(BaseCommand):
301
301
  # if engine == 'django.db.backends.postgresql':
302
302
  # foralltables(using, "ALTER TABLE {} ENABLE TRIGGER ALL;")
303
303
 
304
- # if buildcache: # why did we add this at all?
305
- # settings.SITE.build_site_cache(verbosity=verbosity)
306
-
307
304
  settings.SITE.clear_site_config()
308
305
 
309
306
  # dblogger.info("Lino initdb %s done on database %s.", args, dbname)
lino/modlib/__init__.py CHANGED
@@ -30,7 +30,6 @@ Front ends
30
30
  .. autosummary::
31
31
  :toctree:
32
32
 
33
- bootstrap5
34
33
  extjs
35
34
 
36
35
  Optional features
@@ -1,2 +1,2 @@
1
1
  The content of directory `static/bootstrap-5.3.7` comes from
2
- http://getbootstrap.com
2
+ https://getbootstrap.com
@@ -18,44 +18,40 @@ from lino.api.ad import Plugin
18
18
 
19
19
  class Plugin(Plugin):
20
20
  # ui_label = _("Bootstrap")
21
- ui_handle_attr_name = "bootstrap5_handle"
22
-
23
21
  # site_js_snippets = ['snippets/plain.js']
24
-
25
22
  needs_plugins = ["lino.modlib.jinja"]
26
-
27
- url_prefix = "bs5"
28
-
29
23
  media_name = "bootstrap-5.3.7"
30
-
31
24
  # media_base_url = "http://maxcdn.bootstrapcdn.com/bootstrap/5.3.7/"
32
25
 
33
- def on_ui_init(self, kernel):
34
- from .renderer import Renderer
35
-
36
- self.renderer = Renderer(self)
37
- # ui.bs5_renderer = self.renderer
38
-
39
- def get_patterns(self):
40
- # from django.conf.urls import url
41
- from django.urls import re_path as url
42
- from . import views
43
-
44
- rx = "^"
45
-
46
- urls = [
47
- # url(rx + r'/?$', views.Index.as_view()),
48
- url(rx + r"$", views.Index.as_view()),
49
- url(rx + r"auth", views.Authenticate.as_view()),
50
- # NB app_label must be at least 3 chars long to avoid clash with
51
- # publisher patterns
52
- url(rx + r"(?P<app_label>\w\w\w+)/(?P<actor>\w+)$", views.List.as_view()),
53
- url(
54
- rx + r"(?P<app_label>\w\w\w+)/(?P<actor>\w+)/(?P<pk>.+)$",
55
- views.Element.as_view(),
56
- ),
57
- ]
58
- return urls
26
+ # ui_handle_attr_name = "bootstrap5_handle"
27
+ # url_prefix = "bs5"
28
+ #
29
+ # def on_ui_init(self, kernel):
30
+ # from .renderer import Renderer
31
+ #
32
+ # self.renderer = Renderer(self)
33
+ # # ui.bs5_renderer = self.renderer
34
+ #
35
+ # def get_patterns(self):
36
+ # # from django.conf.urls import url
37
+ # from django.urls import re_path as url
38
+ # from . import views
39
+ #
40
+ # rx = "^"
41
+ #
42
+ # urls = [
43
+ # # url(rx + r'/?$', views.Index.as_view()),
44
+ # url(rx + r"$", views.Index.as_view()),
45
+ # url(rx + r"auth", views.Authenticate.as_view()),
46
+ # # NB app_label must be at least 3 chars long to avoid clash with
47
+ # # publisher patterns
48
+ # url(rx + r"(?P<app_label>\w\w\w+)/(?P<actor>\w+)$", views.List.as_view()),
49
+ # url(
50
+ # rx + r"(?P<app_label>\w\w\w+)/(?P<actor>\w+)/(?P<pk>.+)$",
51
+ # views.Element.as_view(),
52
+ # ),
53
+ # ]
54
+ # return urls
59
55
 
60
56
  def get_detail_url(self, ar, actor, pk, *args, **kw):
61
57
  return self.build_plain_url(
@@ -64,10 +60,10 @@ class Plugin(Plugin):
64
60
 
65
61
  def get_used_libs(self, html=False):
66
62
  if html is not None:
67
- yield ("Bootstrap", "5.3.7", "http://getbootstrap.com")
63
+ yield ("Bootstrap", "5.3.7", "https://getbootstrap.com")
68
64
  # yield ("jQuery", '?', "http://...")
69
65
 
70
- def get_index_view(self):
71
- from . import views
72
-
73
- return views.Index.as_view()
66
+ # def get_index_view(self):
67
+ # from . import views
68
+ #
69
+ # return views.Index.as_view()
@@ -6,7 +6,11 @@
6
6
  <link rel="stylesheet" href="{{site.plugins.bootstrap5.build_lib_url('css','bootstrap.css')}}" type="text/css">
7
7
  <link rel="stylesheet" href="{{site.build_static_url('bootstrap.css')}}" type="text/css">
8
8
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/timepicker@1.11.12/jquery.timepicker.min.css" type="text/css">
9
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@enzedonline/quill-blot-formatter2/dist/css/quill-blot-formatter2.css">
10
+ <link rel="stylesheet" href="https://unpkg.com/primeicons/primeicons.css"/>
11
+ {# Do we need jquery? Isn't this an invalid URL?
9
12
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
13
+ #}
10
14
  <link rel="shortcut icon" type="image/png" href="{{ site.build_static_url('favicon2.ico') }}" />
11
15
 
12
16
  </head><body>
@@ -2,29 +2,29 @@
2
2
  # Copyright 2014-2023 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
- from django.conf import settings
6
- from lino.core.tables import AbstractTable
7
- from lino.core.roles import Expert
5
+ # from django.conf import settings
6
+ # from lino.core.tables import AbstractTable
7
+ # from lino.core.roles import Expert
8
+ #
9
+ # from lino.api import dd, _
8
10
 
9
- from lino.api import dd, _
10
11
 
12
+ # class ShowAsHtml(dd.Action):
13
+ # label = _("HTML")
14
+ # help_text = _("Show this table in Bootstrap3 interface")
15
+ # icon_name = "html"
16
+ # ui5_icon_name = "sap-icon://attachment-html"
17
+ # sort_index = -15
18
+ # select_rows = False
19
+ # default_format = "ajax"
20
+ # preprocessor = "Lino.get_current_grid_config"
21
+ # callable_from = "t"
22
+ # required_roles = dd.login_required(Expert)
23
+ #
24
+ # def run_from_ui(self, ar, **kw):
25
+ # url = dd.plugins.bootstrap5.renderer.get_request_url(ar)
26
+ # ar.success(open_url=url)
27
+ #
11
28
 
12
- class ShowAsHtml(dd.Action):
13
- label = _("HTML")
14
- help_text = _("Show this table in Bootstrap3 interface")
15
- icon_name = "html"
16
- ui5_icon_name = "sap-icon://attachment-html"
17
- sort_index = -15
18
- select_rows = False
19
- default_format = "ajax"
20
- preprocessor = "Lino.get_current_grid_config"
21
- callable_from = "t"
22
- required_roles = dd.login_required(Expert)
23
-
24
- def run_from_ui(self, ar, **kw):
25
- url = dd.plugins.bootstrap5.renderer.get_request_url(ar)
26
- ar.success(open_url=url)
27
-
28
-
29
- if settings.SITE.default_ui != "lino.modlib.bootstrap5":
30
- AbstractTable.show_as_html = ShowAsHtml()
29
+ # if settings.SITE.default_ui != "lino.modlib.bootstrap5":
30
+ # AbstractTable.show_as_html = ShowAsHtml()
@@ -4,30 +4,26 @@
4
4
  """Views for `lino.modlib.bootstrap5`.
5
5
 
6
6
  """
7
- from past.utils import old_div
8
7
 
9
8
  from django import http
10
9
  from django.conf import settings
11
10
  from django.views.generic import View
12
- from django.core import exceptions
13
11
  from django.utils.translation import gettext as _
14
12
  from django.utils.translation import get_language
15
13
  from django.utils.decorators import method_decorator
16
14
  from django.views.decorators.csrf import ensure_csrf_cookie
17
-
18
15
  # from django.contrib import auth
19
16
  from lino.core import auth
20
-
21
17
  # from lino.api import dd
22
18
  from lino.core import constants
23
-
24
19
  # from lino.core import auth
25
20
  from lino.core.requests import BaseRequest
26
21
  from lino.core.tables import AbstractTable
27
22
  from lino.core.views import action_request
28
23
  from lino.core.utils import navinfo
29
24
  from lino.utils.html import E, tostring
30
- from etgen import html as xghtml
25
+
26
+ raise Exception("No longer used since 20250826")
31
27
 
32
28
  PLAIN_PAGE_LENGTH = 15
33
29
 
@@ -78,107 +74,6 @@ def buttons2pager(buttons, title=None):
78
74
  return E.ul(*items, **{"class": "pagination pagination-sm"})
79
75
 
80
76
 
81
- def table2html(ar, as_main=True):
82
- """Represent the given table request as an HTML table.
83
-
84
- `ar` is the request to be rendered, an instance of
85
- :class:`lino.core.requests.ActionRequest`.
86
-
87
- The returned HTML enclosed in a ``<div>`` tag and generated using
88
- :mod:`etgen.html`.
89
-
90
- If `as_main` is True, include additional elements such as a paging
91
- toolbar. (This argument is currently being ignored.)
92
-
93
- """
94
- # as_main = True
95
- t = xghtml.Table()
96
- t.attrib.update(**{"class": "table table-striped table-hover"})
97
- if ar.limit is None:
98
- ar.limit = PLAIN_PAGE_LENGTH
99
- pglen = ar.limit
100
- if ar.offset is None:
101
- page = 1
102
- else:
103
- """
104
- (assuming pglen is 5)
105
- offset page
106
- 0 1
107
- 5 2
108
- """
109
- page = int(old_div(ar.offset, pglen)) + 1
110
-
111
- ar.dump2html(t, ar.sliced_data_iterator, header_links=as_main)
112
- if not as_main:
113
- url = ar.get_request_url() or "#" # open in own window
114
- return E.div(
115
- E.div(
116
- E.div(
117
- E.a(
118
- E.span(**{"class": "glyphicon glyphicon-folder-open"}),
119
- href=url,
120
- style="margin-left: 4px;",
121
- **{"class": "btn btn-default pull-right"},
122
- ),
123
- E.h5(str(ar.get_title()), style="display: inline-block;"),
124
- **{"class": "panel-title"},
125
- ),
126
- **{"class": "panel-heading"},
127
- ),
128
- t.as_element(),
129
- style="display: inline-block;",
130
- **{"class": "panel panel-default"},
131
- )
132
-
133
- buttons = []
134
- kw = dict()
135
- kw = {}
136
- if pglen != PLAIN_PAGE_LENGTH:
137
- kw[constants.URL_PARAM_LIMIT] = pglen
138
-
139
- if page > 1:
140
- kw[constants.URL_PARAM_START] = pglen * (page - 2)
141
- prev_url = ar.get_request_url(**kw)
142
- kw[constants.URL_PARAM_START] = 0
143
- first_url = ar.get_request_url(**kw)
144
- else:
145
- prev_url = None
146
- first_url = None
147
- buttons.append(("<<", _("First page"), first_url))
148
- buttons.append(("<", _("Previous page"), prev_url))
149
-
150
- next_start = pglen * page
151
- if next_start < ar.get_total_count():
152
- kw[constants.URL_PARAM_START] = next_start
153
- next_url = ar.get_request_url(**kw)
154
- last_page = int(old_div((ar.get_total_count() - 1), pglen))
155
- kw[constants.URL_PARAM_START] = pglen * last_page
156
- last_url = ar.get_request_url(**kw)
157
- else:
158
- next_url = None
159
- last_url = None
160
- buttons.append((">", _("Next page"), next_url))
161
- buttons.append((">>", _("Last page"), last_url))
162
-
163
- return E.div(buttons2pager(buttons), t.as_element())
164
-
165
-
166
- def layout2html(ar, elem):
167
- wl = ar.bound_action.get_window_layout()
168
- if wl is None:
169
- raise Exception("{!r} has no window layout".format(ar.bound_action))
170
- # ~ print 20120901, wl.main
171
- lh = wl.get_layout_handle()
172
-
173
- items = list(lh.main.as_plain_html(ar, elem))
174
- # if navigator:
175
- # items.insert(0, navigator)
176
- # ~ print tostring(E.div())
177
- # ~ if len(items) == 0: return ""
178
- return E.form(*items)
179
- # ~ print 20120901, lh.main.__html__(ar)
180
-
181
-
182
77
  class List(View):
183
78
  """Render a list of records."""
184
79
 
@@ -138,7 +138,7 @@ class Checker(dd.Choice):
138
138
  return []
139
139
 
140
140
  def get_responsible_user(self, obj):
141
- return dd.plugins.users.get_demo_user(self, obj)
141
+ return dd.plugins.users.get_demo_user()
142
142
 
143
143
 
144
144
  class Checkers(dd.ChoiceList):
@@ -94,6 +94,7 @@ def objects():
94
94
  # else:
95
95
  # txt = TXT.pop() # txt = "Hackerish comment"
96
96
  body = BODIES.pop()
97
+ # if not body and len(MENTIONED) or SCREENSHOTS:
97
98
  if not body:
98
99
  if SCREENSHOTS is None or i % 2:
99
100
  cmd1 = MENTIONED.pop().obj2memo()