lino 25.6.0__py3-none-any.whl → 25.7.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.
- lino/__init__.py +1 -1
- lino/api/doctest.py +21 -0
- lino/core/actions.py +59 -25
- lino/core/actors.py +38 -16
- lino/core/boundaction.py +16 -0
- lino/core/choicelists.py +7 -7
- lino/core/constants.py +3 -0
- lino/core/dashboard.py +1 -0
- lino/core/dbtables.py +1 -1
- lino/core/elems.py +38 -13
- lino/core/fields.py +20 -11
- lino/core/kernel.py +8 -0
- lino/core/layouts.py +6 -2
- lino/core/menus.py +3 -6
- lino/core/model.py +5 -4
- lino/core/renderer.py +14 -5
- lino/core/requests.py +8 -7
- lino/core/signals.py +1 -0
- lino/core/site.py +48 -28
- lino/core/store.py +4 -2
- lino/core/tables.py +23 -10
- lino/core/utils.py +4 -1
- lino/core/workflows.py +2 -1
- lino/help_texts.py +1 -2
- lino/management/commands/prep.py +2 -2
- lino/management/commands/show.py +8 -10
- lino/mixins/__init__.py +14 -13
- lino/mixins/periods.py +2 -0
- lino/mixins/sequenced.py +1 -1
- lino/modlib/about/models.py +4 -3
- lino/modlib/checkdata/__init__.py +42 -36
- lino/modlib/checkdata/choicelists.py +9 -1
- lino/modlib/checkdata/fixtures/checkdata.py +4 -2
- lino/modlib/checkdata/models.py +9 -2
- lino/modlib/comments/models.py +4 -3
- lino/modlib/extjs/ext_renderer.py +4 -4
- lino/modlib/extjs/views.py +8 -2
- lino/modlib/gfks/fields.py +1 -1
- lino/modlib/help/__init__.py +3 -3
- lino/modlib/help/config/makehelp/conf.tpl.py +2 -2
- lino/modlib/help/fixtures/demo2.py +6 -1
- lino/modlib/help/management/commands/makehelp.py +4 -1
- lino/modlib/help/models.py +2 -1
- lino/modlib/help/utils.py +12 -6
- lino/modlib/linod/choicelists.py +57 -4
- lino/modlib/linod/fixtures/{linod.py → checkdata.py} +3 -13
- lino/modlib/linod/management/commands/linod.py +0 -13
- lino/modlib/linod/mixins.py +8 -0
- lino/modlib/linod/models.py +29 -30
- lino/modlib/memo/__init__.py +7 -7
- lino/modlib/memo/management/__init__,py +0 -0
- lino/modlib/memo/management/commands/__init__.py +0 -0
- lino/modlib/memo/management/commands/removeurls.py +67 -0
- lino/modlib/memo/mixins.py +1 -9
- lino/modlib/memo/parser.py +1 -1
- lino/modlib/notify/config/notify/summary.eml +5 -2
- lino/modlib/notify/fixtures/demo2.py +5 -6
- lino/modlib/notify/models.py +9 -10
- lino/modlib/periods/__init__.py +11 -8
- lino/modlib/periods/choicelists.py +16 -10
- lino/modlib/periods/models.py +45 -45
- lino/modlib/summaries/fixtures/checksummaries.py +4 -2
- lino/modlib/system/models.py +17 -18
- lino/modlib/uploads/fixtures/demo.py +9 -3
- lino/modlib/uploads/mixins.py +5 -2
- lino/modlib/uploads/models.py +15 -9
- lino/modlib/uploads/utils.py +4 -1
- lino/modlib/users/__init__.py +59 -18
- lino/modlib/users/actions.py +24 -20
- lino/modlib/users/fixtures/demo_users.py +2 -35
- lino/modlib/users/mixins.py +3 -4
- lino/modlib/users/models.py +53 -13
- lino/modlib/users/ui.py +30 -16
- lino/modlib/users/utils.py +5 -6
- lino/projects/std/settings.py +1 -1
- lino/sphinxcontrib/logo/templates/footer.html +1 -0
- lino/utils/ajax.py +1 -1
- lino/utils/cycler.py +5 -0
- lino/utils/dbhash.py +4 -9
- lino/utils/dpy.py +2 -2
- lino/utils/format_date.py +4 -3
- lino/utils/html.py +13 -5
- lino/utils/jsgen.py +1 -1
- lino/utils/quantities.py +8 -0
- lino/utils/soup.py +75 -94
- {lino-25.6.0.dist-info → lino-25.7.0.dist-info}/METADATA +1 -1
- {lino-25.6.0.dist-info → lino-25.7.0.dist-info}/RECORD +90 -87
- {lino-25.6.0.dist-info → lino-25.7.0.dist-info}/WHEEL +0 -0
- {lino-25.6.0.dist-info → lino-25.7.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.6.0.dist-info → lino-25.7.0.dist-info}/licenses/COPYING +0 -0
lino/management/commands/prep.py
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
from django.core.management import call_command
|
6
6
|
from django.core.management.base import BaseCommand, CommandError
|
7
7
|
from django.conf import settings
|
8
|
-
from lino.
|
8
|
+
from lino.core.signals import database_prepared
|
9
9
|
|
10
10
|
|
11
11
|
class Command(BaseCommand):
|
@@ -62,4 +62,4 @@ class Command(BaseCommand):
|
|
62
62
|
kwargs["removemedia"] = True
|
63
63
|
call_command("initdb", *args, **kwargs)
|
64
64
|
|
65
|
-
|
65
|
+
database_prepared.send(self)
|
lino/management/commands/show.py
CHANGED
@@ -2,25 +2,23 @@
|
|
2
2
|
# Copyright 2013-2021 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
|
-
import argparse
|
6
5
|
from lino.api import rt
|
7
6
|
from django.core.management.base import BaseCommand, CommandError
|
8
7
|
|
8
|
+
|
9
9
|
class Command(BaseCommand):
|
10
10
|
help = "Show the content of a specified table to standard output."
|
11
11
|
|
12
12
|
# args = "action_spec [options] [args ...]"
|
13
13
|
|
14
14
|
def add_arguments(self, parser):
|
15
|
-
(
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
help="The username to act as. Default is `None`.",
|
23
|
-
),
|
15
|
+
parser.add_argument(
|
16
|
+
"-u",
|
17
|
+
"--username",
|
18
|
+
action="store",
|
19
|
+
dest="username",
|
20
|
+
default=None,
|
21
|
+
help="The username to act as. Default is `None`.",
|
24
22
|
)
|
25
23
|
parser.add_argument(
|
26
24
|
"-l",
|
lino/mixins/__init__.py
CHANGED
@@ -61,7 +61,7 @@ class Contactable(model.Model):
|
|
61
61
|
email.
|
62
62
|
"""
|
63
63
|
|
64
|
-
class Meta
|
64
|
+
class Meta:
|
65
65
|
abstract = True
|
66
66
|
|
67
67
|
email = models.EmailField(_("e-mail address"), blank=True)
|
@@ -78,7 +78,7 @@ class Phonable(model.Model):
|
|
78
78
|
phone.
|
79
79
|
"""
|
80
80
|
|
81
|
-
class Meta
|
81
|
+
class Meta:
|
82
82
|
abstract = True
|
83
83
|
|
84
84
|
url = models.URLField(_("URL"), blank=True)
|
@@ -105,7 +105,7 @@ class Modified(model.Model):
|
|
105
105
|
you explicitly call :meth:`touch`.
|
106
106
|
"""
|
107
107
|
|
108
|
-
class Meta
|
108
|
+
class Meta:
|
109
109
|
abstract = True
|
110
110
|
|
111
111
|
modified = models.DateTimeField(_("Modified"), editable=False, null=True)
|
@@ -132,7 +132,7 @@ class Created(model.Model):
|
|
132
132
|
because their deserialization would be problematic.
|
133
133
|
"""
|
134
134
|
|
135
|
-
class Meta
|
135
|
+
class Meta:
|
136
136
|
abstract = True
|
137
137
|
|
138
138
|
created = models.DateTimeField(_("Created"), editable=False)
|
@@ -153,7 +153,7 @@ class CreatedModified(Created, Modified):
|
|
153
153
|
|
154
154
|
"""
|
155
155
|
|
156
|
-
class Meta
|
156
|
+
class Meta:
|
157
157
|
abstract = True
|
158
158
|
|
159
159
|
|
@@ -175,7 +175,7 @@ class ProjectRelated(model.Model):
|
|
175
175
|
<lino.core.fields.DummyField>`.
|
176
176
|
"""
|
177
177
|
|
178
|
-
class Meta
|
178
|
+
class Meta:
|
179
179
|
abstract = True
|
180
180
|
|
181
181
|
project = fields.ForeignKey(
|
@@ -186,11 +186,12 @@ class ProjectRelated(model.Model):
|
|
186
186
|
)
|
187
187
|
|
188
188
|
def get_related_project(self):
|
189
|
-
if settings.SITE.project_model:
|
190
|
-
|
189
|
+
# if settings.SITE.project_model:
|
190
|
+
# When project_model is None, project is a dummy field which always returns None
|
191
|
+
return self.project
|
191
192
|
|
192
193
|
# def on_create(self, ar):
|
193
|
-
# super(
|
194
|
+
# super().on_create(ar)
|
194
195
|
# print(20200327, ar.actor.master_key, ar.master_instance)
|
195
196
|
# if ar.actor.master_key and ar.actor.master_key == "project":
|
196
197
|
# self.project = ar.master_instance
|
@@ -213,24 +214,24 @@ class ProjectRelated(model.Model):
|
|
213
214
|
"""
|
214
215
|
if isinstance(controllable, ProjectRelated):
|
215
216
|
controllable.project = self.project
|
216
|
-
super(
|
217
|
+
super().update_owned_instance(controllable)
|
217
218
|
|
218
219
|
def get_mailable_recipients(self):
|
219
220
|
if isinstance(self.project, settings.SITE.models.contacts.Partner):
|
220
221
|
if self.project.email:
|
221
222
|
yield ("to", self.project)
|
222
|
-
for r in super(
|
223
|
+
for r in super().get_mailable_recipients():
|
223
224
|
yield r
|
224
225
|
|
225
226
|
def get_postable_recipients(self):
|
226
227
|
if isinstance(self.project, settings.SITE.models.contacts.Partner):
|
227
228
|
yield self.project
|
228
|
-
for p in super(
|
229
|
+
for p in super().get_postable_recipients():
|
229
230
|
yield p
|
230
231
|
|
231
232
|
@classmethod
|
232
233
|
def get_simple_parameters(cls):
|
233
|
-
for p in super(
|
234
|
+
for p in super().get_simple_parameters():
|
234
235
|
yield p
|
235
236
|
# if settings.SITE.project_model:
|
236
237
|
yield "project"
|
lino/mixins/periods.py
CHANGED
@@ -18,6 +18,7 @@ from django.utils.translation import gettext_lazy as _
|
|
18
18
|
from django.utils.translation import pgettext_lazy as pgettext
|
19
19
|
from django.core.exceptions import ValidationError
|
20
20
|
from django.utils.timezone import is_aware
|
21
|
+
from asgiref.sync import sync_to_async
|
21
22
|
|
22
23
|
from lino.utils import last_day_of_month
|
23
24
|
from lino.api import dd
|
@@ -276,6 +277,7 @@ class DateRange(DateRangeObservable):
|
|
276
277
|
return False
|
277
278
|
return True
|
278
279
|
|
280
|
+
|
279
281
|
DateRange.set_widget_options("start_date", width=10)
|
280
282
|
DateRange.set_widget_options("end_date", width=10)
|
281
283
|
|
lino/mixins/sequenced.py
CHANGED
@@ -325,7 +325,7 @@ class Sequenced(Duplicable):
|
|
325
325
|
message=_("Renumbered {} of {} siblings.").format(n, qs.count()))
|
326
326
|
ar.set_response(refresh_all=True)
|
327
327
|
|
328
|
-
@fields.displayfield("⇵")
|
328
|
+
@fields.displayfield("⇵", wildcard_data_elem=True)
|
329
329
|
def dndreorder(self, ar):
|
330
330
|
"""A place holder column for drag and drop row reorder on :term:`React front end`
|
331
331
|
|
lino/modlib/about/models.py
CHANGED
@@ -8,7 +8,7 @@ import datetime
|
|
8
8
|
# from django.contrib.humanize.templatetags.humanize import naturaltime
|
9
9
|
from django.utils.translation import gettext_lazy as _
|
10
10
|
from django.utils.translation import gettext
|
11
|
-
from django.utils.html import mark_safe
|
11
|
+
from django.utils.html import mark_safe, format_html
|
12
12
|
from django.conf import settings
|
13
13
|
|
14
14
|
from lino.utils.report import EmptyTable
|
@@ -64,7 +64,7 @@ class About(EmptyTable):
|
|
64
64
|
body += "".join([tostring(e) for e in site.welcome_html()])
|
65
65
|
|
66
66
|
for p in site.sorted_plugins:
|
67
|
-
for i in p.get_site_info():
|
67
|
+
for i in p.get_site_info(ar):
|
68
68
|
body += i
|
69
69
|
|
70
70
|
if site.languages:
|
@@ -142,7 +142,8 @@ class About(EmptyTable):
|
|
142
142
|
)
|
143
143
|
)
|
144
144
|
)
|
145
|
-
body =
|
145
|
+
body = mark_safe(body)
|
146
|
+
body = format_html("<div>{}</div>", body)
|
146
147
|
# return js_code(rt.html_text(body))
|
147
148
|
# return rt.html_text(body)
|
148
149
|
# return mark_safe(body)
|
@@ -14,6 +14,7 @@ See :doc:`/plugins/checkdata`.
|
|
14
14
|
"""
|
15
15
|
|
16
16
|
from lino.api import ad, _
|
17
|
+
from lino.core.exceptions import ChangedAPI
|
17
18
|
|
18
19
|
|
19
20
|
class Plugin(ad.Plugin):
|
@@ -21,42 +22,44 @@ class Plugin(ad.Plugin):
|
|
21
22
|
|
22
23
|
verbose_name = _("Checkdata")
|
23
24
|
needs_plugins = ["lino.modlib.users", "lino.modlib.gfks",
|
24
|
-
|
25
|
+
"lino.modlib.office", "lino.modlib.linod"]
|
26
|
+
|
27
|
+
fix_in_background = True
|
25
28
|
|
26
29
|
# plugin settings
|
27
|
-
responsible_user = None # the username (a string)
|
28
|
-
"""
|
29
|
-
|
30
|
-
The :attr:`username <lino.modlib.users.User.username>`
|
31
|
-
of the **main checkdata responsible**, i.e. a designated
|
32
|
-
user who will be attributed to checkdata messages for which
|
33
|
-
no *specific responible* could be designated (returned by the
|
34
|
-
checker's :meth:`get_responsible_user
|
35
|
-
<lino.modlib.checkdata.Checker.get_responsible_user>`
|
36
|
-
method).
|
37
|
-
|
38
|
-
The default value for this is `None`, except on a demo site
|
39
|
-
(i.e. which has :attr:`is_demo_site
|
40
|
-
<lino.core.site.Site.is_demo_site>` set to `True`) where it is
|
41
|
-
``"'robin'``.
|
42
|
-
|
43
|
-
"""
|
44
|
-
|
45
|
-
_responsible_user = None # the cached User object
|
46
|
-
|
47
|
-
def get_responsible_user(self, checker, obj):
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
30
|
+
# responsible_user = None # the username (a string)
|
31
|
+
# """
|
32
|
+
#
|
33
|
+
# The :attr:`username <lino.modlib.users.User.username>`
|
34
|
+
# of the **main checkdata responsible**, i.e. a designated
|
35
|
+
# user who will be attributed to checkdata messages for which
|
36
|
+
# no *specific responible* could be designated (returned by the
|
37
|
+
# checker's :meth:`get_responsible_user
|
38
|
+
# <lino.modlib.checkdata.Checker.get_responsible_user>`
|
39
|
+
# method).
|
40
|
+
#
|
41
|
+
# The default value for this is `None`, except on a demo site
|
42
|
+
# (i.e. which has :attr:`is_demo_site
|
43
|
+
# <lino.core.site.Site.is_demo_site>` set to `True`) where it is
|
44
|
+
# ``"'robin'``.
|
45
|
+
#
|
46
|
+
# """
|
47
|
+
|
48
|
+
# _responsible_user = None # the cached User object
|
49
|
+
#
|
50
|
+
# def get_responsible_user(self, checker, obj):
|
51
|
+
# if self.responsible_user is None:
|
52
|
+
# return None
|
53
|
+
# if self._responsible_user is None:
|
54
|
+
# User = self.site.models.users.User
|
55
|
+
# try:
|
56
|
+
# self._responsible_user = User.objects.get(
|
57
|
+
# username=self.responsible_user)
|
58
|
+
# except User.DoesNotExist:
|
59
|
+
# msg = "Invalid username '{0}' in `responsible_user` "
|
60
|
+
# msg = msg.format(self.responsible_user)
|
61
|
+
# raise Exception(msg)
|
62
|
+
# return self._responsible_user
|
60
63
|
|
61
64
|
def on_plugins_loaded(self, site):
|
62
65
|
"""Set :attr:`responsible_user` to ``"'robin'`` if this is a demo site
|
@@ -64,8 +67,11 @@ class Plugin(ad.Plugin):
|
|
64
67
|
|
65
68
|
"""
|
66
69
|
super().on_plugins_loaded(site)
|
67
|
-
if
|
68
|
-
|
70
|
+
if hasattr(self, 'responsible_user'):
|
71
|
+
raise ChangedAPI(
|
72
|
+
"20250703 checkdata.responsible_user is replaced by users.demo_username")
|
73
|
+
# if site.is_demo_site and self.responsible_user is None:
|
74
|
+
# self.configure(responsible_user="robin")
|
69
75
|
|
70
76
|
def post_site_startup(self, site):
|
71
77
|
super().post_site_startup(site)
|
@@ -49,6 +49,9 @@ class Checker(dd.Choice):
|
|
49
49
|
text = self.verbose_name
|
50
50
|
super().__init__(value, text, None, **kwargs)
|
51
51
|
|
52
|
+
def __str__(self):
|
53
|
+
return self.value
|
54
|
+
|
52
55
|
@classmethod
|
53
56
|
def activate(cls, **kwargs):
|
54
57
|
if cls.self is not None:
|
@@ -56,6 +59,11 @@ class Checker(dd.Choice):
|
|
56
59
|
cls.self = cls(**kwargs)
|
57
60
|
Checkers.add_item_instance(cls.self)
|
58
61
|
|
62
|
+
# @classmethod
|
63
|
+
# def fix_problems_silently(cls, ar, obj=None):
|
64
|
+
# for fixable, msg in cls.self.get_checkdata_problems(ar, obj, True):
|
65
|
+
# pass
|
66
|
+
|
59
67
|
@classmethod
|
60
68
|
def update_unbound_problems(cls, ar, **kwargs):
|
61
69
|
assert cls.self.model is None
|
@@ -130,7 +138,7 @@ class Checker(dd.Choice):
|
|
130
138
|
return []
|
131
139
|
|
132
140
|
def get_responsible_user(self, obj):
|
133
|
-
return dd.plugins.
|
141
|
+
return dd.plugins.users.get_demo_user(self, obj)
|
134
142
|
|
135
143
|
|
136
144
|
class Checkers(dd.ChoiceList):
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
-
# Copyright 2015 Rumma & Ko Ltd
|
2
|
+
# Copyright 2015-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
"""Runs the :manage:`checkdata` management command with `--fix`
|
5
5
|
option.
|
@@ -7,8 +7,10 @@ option.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from django.core.management import call_command
|
10
|
+
from lino.api import dd
|
10
11
|
|
11
12
|
|
12
13
|
def objects():
|
13
|
-
|
14
|
+
if not dd.is_installed("linod"):
|
15
|
+
call_command("checkdata", fix=True)
|
14
16
|
return []
|
lino/modlib/checkdata/models.py
CHANGED
@@ -317,6 +317,13 @@ def check_instance(ar, obj, **kwargs):
|
|
317
317
|
print(msg)
|
318
318
|
|
319
319
|
|
320
|
+
def fix_instance(ar, obj, **kwargs):
|
321
|
+
kwargs['fix'] = True
|
322
|
+
for chk in get_checkers_for(obj.__class__):
|
323
|
+
for fixable, msg in chk.check_instance(ar, obj, **kwargs):
|
324
|
+
pass
|
325
|
+
|
326
|
+
|
320
327
|
def get_checkable_models(*args, only_auto=False):
|
321
328
|
checkable_models = OrderedDict()
|
322
329
|
for chk in Checkers.get_list_items():
|
@@ -407,8 +414,8 @@ def check_data(ar, args=[], fix=True, prune=False):
|
|
407
414
|
ar.logger.info(msg, done, what, found, fixed)
|
408
415
|
|
409
416
|
|
410
|
-
@background_task(every_unit="daily", every=1)
|
417
|
+
@background_task(every_unit="daily", every=1, run_after='generate_calendar_entries')
|
411
418
|
def checkdata(ar):
|
412
419
|
"""Run all data checkers."""
|
413
|
-
check_data(ar, fix=
|
420
|
+
check_data(ar, fix=dd.plugins.checkdata.fix_in_background)
|
414
421
|
# rt.login().run(settings.SITE.site_config.run_checkdata)
|
lino/modlib/comments/models.py
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
5
|
# from html import escape
|
6
|
-
from .ui import *
|
7
6
|
from lino.modlib.checkdata.choicelists import Checker
|
8
7
|
from django.contrib.humanize.templatetags.humanize import naturaltime
|
9
8
|
from django.db import models
|
@@ -14,7 +13,7 @@ from django.contrib.contenttypes.models import ContentType
|
|
14
13
|
from django.conf import settings
|
15
14
|
# from lino.utils.html import E, tostring, fromstring
|
16
15
|
|
17
|
-
from lino.api import dd, rt, _
|
16
|
+
from lino.api import dd, rt, gettext, _
|
18
17
|
|
19
18
|
from lino.core.requests import BaseRequest
|
20
19
|
from lino.mixins import CreatedModified, BabelNamed
|
@@ -30,6 +29,8 @@ from .mixins import Commentable, MyEmotionField
|
|
30
29
|
from .roles import CommentsReader, CommentsStaff
|
31
30
|
# from .choicelists import PublishAllComments, PublishComment
|
32
31
|
|
32
|
+
from .ui import *
|
33
|
+
|
33
34
|
|
34
35
|
class CommentType(BabelNamed):
|
35
36
|
class Meta(object):
|
@@ -287,7 +288,7 @@ class Comment(
|
|
287
288
|
|
288
289
|
def after_ui_save(self, ar, cw):
|
289
290
|
super().after_ui_save(ar, cw)
|
290
|
-
if self.
|
291
|
+
if self.owner is not None:
|
291
292
|
self.owner.on_commented(self, ar, cw)
|
292
293
|
|
293
294
|
def full_clean(self):
|
@@ -210,7 +210,7 @@ class ExtRenderer(JsCacheRenderer):
|
|
210
210
|
label = str(label or ba.get_button_label())
|
211
211
|
uri = self.js2url(self.action_call(ar, ba, status or {}))
|
212
212
|
return self.href_button_action(
|
213
|
-
ba, uri, label, title or ba.
|
213
|
+
ba, uri, label, title or ba.get_help_text(), **kw
|
214
214
|
)
|
215
215
|
|
216
216
|
def quick_manage_toolbar(self, ar, obj):
|
@@ -866,7 +866,7 @@ class ExtRenderer(JsCacheRenderer):
|
|
866
866
|
# ~ text=unicode(a.label),
|
867
867
|
)
|
868
868
|
|
869
|
-
if
|
869
|
+
if (help_text := ba.get_help_text()) is not None:
|
870
870
|
# if a.__class__.__name__ in ('ChangePassword', 'SubmitDetail'):
|
871
871
|
# logger.info("20160829 a2btn() %r %r", a, str(a.help_text))
|
872
872
|
|
@@ -874,7 +874,7 @@ class ExtRenderer(JsCacheRenderer):
|
|
874
874
|
# iconCls. On a button which has only text we must use
|
875
875
|
# Lino.quicktip_renderer. But I didn't find out why this
|
876
876
|
# doesn't seem to work.
|
877
|
-
kw.update(tooltip=
|
877
|
+
kw.update(tooltip=help_text, tooltipType="title")
|
878
878
|
# if not a.icon_name:
|
879
879
|
# kw.update(tooltipType='title')
|
880
880
|
# kw.update(listen ers=dict(render=js_code(
|
@@ -1496,7 +1496,7 @@ class ExtRenderer(JsCacheRenderer):
|
|
1496
1496
|
either `data_record` or a `record_id`.
|
1497
1497
|
|
1498
1498
|
Usually `data_record`, except if it is a `file upload
|
1499
|
-
<https://docs.djangoproject.com/en/5.
|
1499
|
+
<https://docs.djangoproject.com/en/5.2/topics/http/file-uploads/>`_
|
1500
1500
|
where some mysterious decoding problems (:blogref:`20120209`)
|
1501
1501
|
force us to return a `record_id` which has the same visible
|
1502
1502
|
result but using an additional GET.
|
lino/modlib/extjs/views.py
CHANGED
@@ -330,6 +330,7 @@ class ApiElement(View):
|
|
330
330
|
vm = test_version_mismatch(request)
|
331
331
|
if vm and settings.SITE.kernel.editing_front_end.app_label == "react":
|
332
332
|
return json_response(vm)
|
333
|
+
|
333
334
|
# this is also used by the react front end
|
334
335
|
rpt = requested_actor(app_label, actor)
|
335
336
|
# if not rpt.get_view_permission(request.user.user_type):
|
@@ -341,12 +342,17 @@ class ApiElement(View):
|
|
341
342
|
if action_name:
|
342
343
|
ba = rpt.get_url_action(action_name)
|
343
344
|
if ba is None:
|
344
|
-
|
345
|
+
msg = f"{rpt} has no action {action_name}"
|
346
|
+
print(msg)
|
347
|
+
raise http.Http404(msg)
|
345
348
|
else:
|
346
349
|
ba = rpt.detail_action
|
347
350
|
if ba is None:
|
348
|
-
|
351
|
+
msg = f"{rpt} has no detail_action"
|
352
|
+
print(msg)
|
353
|
+
raise http.Http404(msg)
|
349
354
|
|
355
|
+
# print(f"20250608 {rpt} {action_name}")
|
350
356
|
fmt = request.GET.get(constants.URL_PARAM_FORMAT,
|
351
357
|
ba.action.default_format)
|
352
358
|
|
lino/modlib/gfks/fields.py
CHANGED
@@ -75,7 +75,7 @@ if settings.SITE.is_installed("contenttypes"):
|
|
75
75
|
|
76
76
|
def deconstruct(self):
|
77
77
|
# needed for Django 1.7
|
78
|
-
# https://docs.djangoproject.com/en/5.
|
78
|
+
# https://docs.djangoproject.com/en/5.2/howto/custom-model-fields/#custom-field-deconstruct-method
|
79
79
|
|
80
80
|
name, path, args, kwargs = super().deconstruct()
|
81
81
|
args = [self.type_field]
|
lino/modlib/help/__init__.py
CHANGED
@@ -66,10 +66,10 @@ class Plugin(ad.Plugin):
|
|
66
66
|
# site.install_help_text(ba.action, ba.action.__class__)
|
67
67
|
if a.model is not None:
|
68
68
|
self.htl.install_help_text(
|
69
|
-
ba
|
69
|
+
ba, a.model, ba.action.action_name
|
70
70
|
)
|
71
|
-
self.htl.install_help_text(ba
|
72
|
-
self.htl.install_help_text(ba.
|
71
|
+
self.htl.install_help_text(ba, a, ba.action.action_name)
|
72
|
+
self.htl.install_help_text(ba.__class__)
|
73
73
|
# htl.install_help_text(
|
74
74
|
# ba.action, ba.action.__class__,
|
75
75
|
# attrname=ba.action.action_name)
|
@@ -18,9 +18,9 @@ from lino.sphinxcontrib import configure ; configure(globals())
|
|
18
18
|
project = "{{settings.SITE.title}}"
|
19
19
|
html_title = "{{settings.SITE.title}}"
|
20
20
|
|
21
|
-
{% if settings.SITE.
|
21
|
+
{% if settings.SITE.plugins.contacts.site_owner %}
|
22
22
|
import datetime
|
23
|
-
copyright = "{} {{settings.SITE.
|
23
|
+
copyright = "{} {{settings.SITE.plugins.contacts.site_owner}}".format(
|
24
24
|
datetime.date.today())
|
25
25
|
{% endif %}
|
26
26
|
|
@@ -14,10 +14,15 @@ if dd.get_plugin_setting("help", "use_contacts"):
|
|
14
14
|
return help.SiteContact(site_contact_type=type, company=company, **kwargs)
|
15
15
|
|
16
16
|
def objects():
|
17
|
-
yield site_contact("owner", settings.SITE.
|
17
|
+
yield site_contact("owner", settings.SITE.plugins.contacts.site_owner)
|
18
18
|
yield site_contact("serveradmin", contacts.Company.objects.get(pk=PS+6))
|
19
19
|
yield site_contact(
|
20
20
|
"hotline",
|
21
21
|
contact_person=contacts.Person.objects.get(pk=PS+13),
|
22
22
|
**dd.babelkw("remark", _("Mon and Fri from 11:30 to 12:00")),
|
23
23
|
)
|
24
|
+
|
25
|
+
else:
|
26
|
+
|
27
|
+
def objects():
|
28
|
+
return []
|
@@ -410,7 +410,10 @@ class Command(GeneratingCommand):
|
|
410
410
|
|
411
411
|
def action2par(self, a):
|
412
412
|
if isinstance(a, BoundAction):
|
413
|
-
a = a.action
|
413
|
+
# a = a.action
|
414
|
+
return shortpar(a.action.action_name, a.action.label,
|
415
|
+
a.get_help_text() or _("See {}.").format(
|
416
|
+
self.refto(a.action)))
|
414
417
|
return shortpar(a.action_name, a.label, self.get_help_text_from_field(a))
|
415
418
|
|
416
419
|
def collect_refs(self, cls, role):
|
lino/modlib/help/models.py
CHANGED
@@ -20,7 +20,8 @@ class OpenHelpWindow(dd.Action):
|
|
20
20
|
# this doesn't look nice. But adding spaces breaks a series of doctests, so
|
21
21
|
# I undid that change:
|
22
22
|
# button_text = " ? "
|
23
|
-
button_text = "?"
|
23
|
+
# button_text = "?"
|
24
|
+
button_text = "🛈"
|
24
25
|
select_rows = False
|
25
26
|
help_text = _("Open Help Window")
|
26
27
|
show_in_plain = True
|
lino/modlib/help/utils.py
CHANGED
@@ -79,8 +79,10 @@ class HelpTextsLoader:
|
|
79
79
|
# if m in self.unhelpful_classes:
|
80
80
|
# continue
|
81
81
|
k, txt = self.get_help_text_for_class(m, attrname)
|
82
|
-
# if attrname == "
|
83
|
-
#
|
82
|
+
# if attrname == "update_guests":
|
83
|
+
# # if str(cls) == "cal.Events":
|
84
|
+
# # if k == "lino_xl.lib.cal.Events.update_guests":
|
85
|
+
# print(f"20250622 {hash(fld)} {cls} {k} {fld.help_text} {txt}")
|
84
86
|
if txt is None:
|
85
87
|
if debug:
|
86
88
|
print(
|
@@ -102,11 +104,15 @@ class HelpTextsLoader:
|
|
102
104
|
cls, attrname, txt, k, fld
|
103
105
|
)
|
104
106
|
)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
fld.help_text = txt
|
108
|
+
# fld._found = True
|
109
|
+
# try:
|
110
|
+
# fld.help_text = txt
|
111
|
+
# except AttributeError as e:
|
112
|
+
# raise AttributeError("20240329 {} {}".format(fld, e))
|
109
113
|
fld._lino_help_ref = k # for makehelp
|
114
|
+
# if attrname == "update_guests":
|
115
|
+
# print(f"20250622 {fld} {cls} {k} {txt}")
|
110
116
|
return
|
111
117
|
if debug:
|
112
118
|
print("20170824 {}.{} : no help_text".format(cls, attrname))
|