lino 25.7.1__py3-none-any.whl → 25.7.2__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 +13 -10
- lino/core/__init__.py +0 -2
- lino/core/actions.py +5 -7
- lino/core/actors.py +2 -162
- lino/core/elems.py +1 -1
- lino/core/fields.py +3 -0
- lino/core/kernel.py +6 -0
- lino/core/layouts.py +5 -7
- lino/core/model.py +1 -0
- lino/core/plugin.py +1 -1
- lino/core/renderer.py +1 -1
- lino/core/requests.py +3 -4
- lino/core/site.py +1 -1
- lino/core/utils.py +6 -4
- lino/help_texts.py +2 -1
- lino/mixins/registrable.py +4 -2
- lino/modlib/extjs/views.py +7 -0
- lino/modlib/linod/__init__.py +1 -1
- lino/modlib/memo/__init__.py +1 -2
- lino/modlib/office/roles.py +0 -1
- lino/modlib/printing/actions.py +2 -6
- lino/modlib/printing/choicelists.py +6 -6
- lino/modlib/printing/mixins.py +2 -2
- lino/modlib/publisher/__init__.py +21 -30
- lino/modlib/publisher/models.py +3 -1
- lino/modlib/publisher/views.py +4 -11
- lino/modlib/weasyprint/__init__.py +9 -0
- lino/modlib/weasyprint/choicelists.py +14 -9
- lino/modlib/weasyprint/config/weasyprint/base.weasy.html +15 -13
- {lino-25.7.1.dist-info → lino-25.7.2.dist-info}/METADATA +1 -1
- {lino-25.7.1.dist-info → lino-25.7.2.dist-info}/RECORD +35 -39
- lino/modlib/forms/__init__.py +0 -51
- lino/modlib/forms/models.py +0 -0
- lino/modlib/forms/renderer.py +0 -74
- lino/modlib/forms/views.py +0 -311
- {lino-25.7.1.dist-info → lino-25.7.2.dist-info}/WHEEL +0 -0
- {lino-25.7.1.dist-info → lino-25.7.2.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.7.1.dist-info → lino-25.7.2.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.7.
|
34
|
+
__version__ = '25.7.2'
|
35
35
|
|
36
36
|
# import setuptools # avoid UserWarning "Distutils was imported before Setuptools"?
|
37
37
|
|
lino/api/doctest.py
CHANGED
@@ -83,6 +83,8 @@ HttpQuery = collections.namedtuple(
|
|
83
83
|
|
84
84
|
# settings.SITE.is_testing = True
|
85
85
|
|
86
|
+
ADMIN_FRONT_END = settings.SITE.kernel.editing_front_end
|
87
|
+
|
86
88
|
|
87
89
|
def get_json_dict(username, uri, an="detail", **kwargs):
|
88
90
|
url = "/api/{0}?fmt=json&an={1}".format(uri, an)
|
@@ -381,27 +383,28 @@ def walk_menu_items(username=None, severe=True):
|
|
381
383
|
mnu = settings.SITE.get_site_menu(user_type)
|
382
384
|
items = []
|
383
385
|
for mi in mnu.walk_items():
|
384
|
-
if mi.bound_action:
|
386
|
+
if ba := mi.bound_action:
|
385
387
|
item = menuselection_text(mi)
|
386
388
|
# item += " ({})".format(mi)
|
387
389
|
item += " : "
|
388
|
-
if isinstance(
|
390
|
+
if isinstance(ba.action, ShowTable) and not mi.params:
|
389
391
|
# url = settings.SITE.kernel.default_ui.renderer.request_handler()
|
390
|
-
# sar =
|
392
|
+
# sar = ba.request(parent=ar)
|
391
393
|
if False:
|
392
|
-
url = ar.get_permalink(
|
394
|
+
url = ar.get_permalink(ba, mi.instance)
|
393
395
|
else:
|
394
|
-
mt =
|
396
|
+
mt = ba.actor
|
395
397
|
baseurl = "api/{}/{}".format(mt.app_label, mt.__name__)
|
396
398
|
kwargs = dict(fmt="json")
|
397
|
-
url = settings.SITE.buildurl(baseurl, **kwargs)
|
399
|
+
# url = settings.SITE.buildurl(baseurl, **kwargs)
|
400
|
+
url = ADMIN_FRONT_END.build_plain_url(baseurl, **kwargs)
|
401
|
+
|
398
402
|
try:
|
399
403
|
response = test_client.get(url)
|
400
404
|
# response = test_client.get(url,
|
401
405
|
# REMOTE_USER=str(username))
|
402
406
|
result = check_json_result(
|
403
|
-
response, None, "GET
|
404
|
-
)
|
407
|
+
response, None, f"GET {url} for user {username}")
|
405
408
|
item += str(result["count"])
|
406
409
|
# Also ask in display_mode "list" to cover assert_safe() bugs.
|
407
410
|
# But not e.g. UserRoles because it's not on a model and doesn't have a list mode
|
@@ -409,10 +412,10 @@ def walk_menu_items(username=None, severe=True):
|
|
409
412
|
kwargs[
|
410
413
|
constants.URL_PARAM_DISPLAY_MODE
|
411
414
|
] = constants.DISPLAY_MODE_LIST
|
412
|
-
url =
|
415
|
+
url = ADMIN_FRONT_END.build_plain_url(baseurl, **kwargs)
|
413
416
|
response = test_client.get(url)
|
414
417
|
result = check_json_result(
|
415
|
-
response, None, "GET
|
418
|
+
response, None, f"GET {url} for user {username}"
|
416
419
|
)
|
417
420
|
# if ar is not None:
|
418
421
|
# sar = mt.request(parent=ar)
|
lino/core/__init__.py
CHANGED
@@ -10,7 +10,6 @@ For some modules the documentation has already been migrated to prosa:
|
|
10
10
|
.. autosummary::
|
11
11
|
:toctree:
|
12
12
|
|
13
|
-
actors
|
14
13
|
boundaction
|
15
14
|
callbacks
|
16
15
|
choicelists
|
@@ -31,7 +30,6 @@ For some modules the documentation has already been migrated to prosa:
|
|
31
30
|
layouts
|
32
31
|
menus
|
33
32
|
merge
|
34
|
-
model
|
35
33
|
permissions
|
36
34
|
renderer
|
37
35
|
requests
|
lino/core/actions.py
CHANGED
@@ -11,7 +11,7 @@ from django.utils.encoding import force_str
|
|
11
11
|
from django.utils.translation import gettext
|
12
12
|
from lino.core import constants
|
13
13
|
from lino.core import keyboard
|
14
|
-
from lino.core.exceptions import ChangedAPI
|
14
|
+
# from lino.core.exceptions import ChangedAPI
|
15
15
|
from .utils import traverse_ddh_fklist
|
16
16
|
from .utils import navinfo
|
17
17
|
from .utils import obj2unicode
|
@@ -37,20 +37,17 @@ class Action(Parametrizable, Permittable):
|
|
37
37
|
save_action_name = None
|
38
38
|
disable_primary_key = True
|
39
39
|
keep_user_values = False
|
40
|
-
icon_name = None
|
40
|
+
icon_name: str = None
|
41
41
|
ui5_icon_name = None
|
42
42
|
react_icon_name = None
|
43
43
|
hidden_elements = frozenset()
|
44
44
|
combo_group = None
|
45
45
|
parameters: dict[str, Any] | None = None
|
46
|
-
|
47
46
|
use_param_panel = False
|
48
47
|
no_params_window = False
|
49
48
|
sort_index = 90
|
50
49
|
help_text = None
|
51
|
-
|
52
50
|
auto_save = True
|
53
|
-
|
54
51
|
extjs_main_panel = None
|
55
52
|
js_handler = None
|
56
53
|
action_name = None
|
@@ -67,6 +64,7 @@ class Action(Parametrizable, Permittable):
|
|
67
64
|
show_in_plain = False
|
68
65
|
show_in_toolbar = True
|
69
66
|
show_in_workflow = False
|
67
|
+
buddy_name: str = None
|
70
68
|
custom_handler = False
|
71
69
|
select_rows = True
|
72
70
|
http_method = "GET"
|
@@ -966,7 +964,7 @@ class ShowEditor(Action):
|
|
966
964
|
show_in_toolbar = False
|
967
965
|
|
968
966
|
def __init__(self, fieldname, *args, **kwargs):
|
969
|
-
self.
|
967
|
+
self.buddy_name = fieldname
|
970
968
|
super().__init__(*args, **kwargs)
|
971
969
|
|
972
970
|
def run_from_ui(self, ar, **kwargs):
|
@@ -978,7 +976,7 @@ class ShowEditor(Action):
|
|
978
976
|
ar.master_instance.__class__).pk
|
979
977
|
})
|
980
978
|
ar.set_response(goto_url=ar.renderer.front_end.build_plain_url(
|
981
|
-
"api", *ar.actor.actor_id.split("."), str(ar.selected_rows[0].pk), self.
|
979
|
+
"api", *ar.actor.actor_id.split("."), str(ar.selected_rows[0].pk), self.buddy_name, **kw))
|
982
980
|
|
983
981
|
|
984
982
|
# Some actions are described by a single action instance used by most actors:
|
lino/core/actors.py
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
"""This defines :class:`Actor` and related classes.
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
Introduction see :doc:`/dev/actors`.
|
7
|
+
Class reference see :doc:`/src/lino/core/actors`.
|
8
8
|
|
9
9
|
"""
|
10
10
|
|
@@ -215,138 +215,21 @@ class ActorMetaClass(type):
|
|
215
215
|
# class Actor(metaclass=ActorMetaClass, type('NewBase', (actions.Parametrizable, Permittable), {}))):
|
216
216
|
class Actor(Parametrizable, Permittable, metaclass=ActorMetaClass):
|
217
217
|
"""
|
218
|
-
The base class for all actors (:term:`data table`). Subclassed by
|
219
|
-
:class:`AbstractTable <lino.core.tables.AbstractTable>`, :class:`Table
|
220
|
-
<lino.core.dbtables.Table>`, :class:`ChoiceList
|
221
|
-
<lino.core.choicelists.ChoiceList>` and :class:`Frame
|
222
|
-
<lino.core.frames.Frame>`.
|
223
|
-
|
224
|
-
.. attribute:: known_values
|
225
|
-
|
226
|
-
A `dict` of `fieldname` -> `value` pairs that specify "known values".
|
227
|
-
|
228
|
-
Requests will automatically be filtered to show only existing
|
229
|
-
records with those values. This is like :attr:`filter`, but new
|
230
|
-
instances created in this Table will automatically have these
|
231
|
-
values set.
|
232
|
-
|
233
|
-
.. attribute:: welcome_message_when_count
|
234
|
-
|
235
|
-
Set this to an integer (e.g. 0) to tell Lino to make a generic
|
236
|
-
welcome message "You have X items in Y" when the number of rows
|
237
|
-
in this table is *greater than* the given integer.
|
238
|
-
|
239
|
-
The following class methods are `None` in the default
|
240
|
-
implementation. Subclass can define them.
|
241
|
-
|
242
|
-
.. classmethod:: get_handle_name(self, ar)
|
243
|
-
|
244
|
-
Most actors use the same UI handle for each request. But
|
245
|
-
e.g. :class:`lino_welfare.modlib.debts.models.PrintEntriesByBudget`
|
246
|
-
and :class:`lino_xl.lib.events.EventsByType` override this to
|
247
|
-
implement dynamic columns depending on it's master_instance.
|
248
|
-
|
249
|
-
|
250
|
-
.. classmethod:: get_welcome_messages(self, ar)
|
251
|
-
|
252
|
-
If a method of this name is defined on an actor, then it must
|
253
|
-
be a class method that takes an :class:`ar
|
254
|
-
<lino.core.requests.BaseRequest>` as single argument and
|
255
|
-
returns or yields a list of :term:`welcome messages <welcome
|
256
|
-
message>` (messages to be displayed in the welcome block of
|
257
|
-
:xfile:`admin_main.html`).
|
258
|
-
|
259
|
-
Note that this handler will be called independently of whether
|
260
|
-
the user has permission to view the actor or not.
|
261
218
|
"""
|
262
219
|
|
263
220
|
_detail_action_class = None
|
264
221
|
|
265
222
|
obvious_fields = set()
|
266
|
-
"""A set of names of fields that are considered :term:`obvious field`. """
|
267
|
-
|
268
223
|
required_roles = set([SiteUser])
|
269
|
-
"""See :doc:`/dev/perms`."""
|
270
|
-
|
271
224
|
model = None
|
272
|
-
"""The model on which this table iterates.
|
273
|
-
|
274
|
-
The :term:`application developer` can specify either the model class itself
|
275
|
-
or a string of type ``'app.Model'``.
|
276
|
-
|
277
|
-
If this is not `None`, it should be a subclass of
|
278
|
-
:class:`lino.core.fields.TableRow`.
|
279
|
-
|
280
|
-
"""
|
281
|
-
|
282
|
-
# actions = None
|
283
|
-
# """An :class:`AttrDict <atelier.utils.AttrDict>` containing the
|
284
|
-
# actions available on this actor.
|
285
|
-
#
|
286
|
-
# """
|
287
|
-
|
288
225
|
only_fields = None
|
289
|
-
|
290
226
|
default_display_modes = None
|
291
|
-
"""
|
292
|
-
Which :term:`display mode` to use in a :term:`slave panel`,
|
293
|
-
depending on available width.
|
294
|
-
|
295
|
-
See :ref:`dg.table.default_display_modes`.
|
296
|
-
"""
|
297
|
-
|
298
227
|
# extra_display_modes = set()
|
299
228
|
# extra_display_modes = {constants.DISPLAY_MODE_SUMMARY}
|
300
229
|
extra_display_modes = {constants.DISPLAY_MODE_HTML}
|
301
|
-
"""
|
302
|
-
A set of additional display modes to make available when rendering this table.
|
303
|
-
|
304
|
-
See :ref:`dg.dd.table.extra_display_modes`.
|
305
|
-
"""
|
306
|
-
|
307
230
|
app_label = None
|
308
|
-
"""
|
309
|
-
Specify this if you want to "override" an existing actor.
|
310
|
-
|
311
|
-
The default value is deduced from the module where the subclass is
|
312
|
-
defined.
|
313
|
-
|
314
|
-
Note that this attribute is not inherited from base classes.
|
315
|
-
|
316
|
-
:func:`lino.core.dbtables.table_factory` also uses this.
|
317
|
-
"""
|
318
|
-
|
319
231
|
master = None
|
320
|
-
"""The class of master instances for requests on this table.
|
321
|
-
|
322
|
-
Application code usually doesn't need to specify this because it
|
323
|
-
is automatically set on actors whose :attr:`master_key` is
|
324
|
-
specified.
|
325
|
-
|
326
|
-
Setting this to something else than `None` will turn the table
|
327
|
-
into a :term:`slave table`.
|
328
|
-
|
329
|
-
If the :attr:`master` is something else than a database model
|
330
|
-
(e.g. a ChoiceList), then the actor must also define a
|
331
|
-
:meth:`get_master_instance` method.
|
332
|
-
|
333
|
-
"""
|
334
|
-
|
335
232
|
master_key = None
|
336
|
-
"""The name of a field of this table's :attr:`model` that
|
337
|
-
points to its :attr:`master`.
|
338
|
-
|
339
|
-
The field named by :attr:`master_key` should usually be a
|
340
|
-
:class:`ForeignKey` field.
|
341
|
-
|
342
|
-
Special cases: :class:`lino_xl.lib.cal.EntriesByGuest` shows the entries
|
343
|
-
having a presence pointing to this guest.
|
344
|
-
|
345
|
-
The :attr:`master_key` is automatically added to :attr:`hidden_columns`.
|
346
|
-
|
347
|
-
|
348
|
-
"""
|
349
|
-
|
350
233
|
details_of_master_template = _("%(details)s of %(master)s")
|
351
234
|
|
352
235
|
parameters = None
|
@@ -458,39 +341,12 @@ class Actor(Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
458
341
|
get_handle_name = None
|
459
342
|
|
460
343
|
abstract = True
|
461
|
-
"""
|
462
|
-
Set this to `True` to prevent Lino from generating useless
|
463
|
-
JavaScript if this is just an abstract base class to be inherited
|
464
|
-
by other actors.
|
465
|
-
|
466
|
-
Note that this class attribute is not inherited to subclasses.
|
467
|
-
|
468
|
-
"""
|
469
344
|
sum_text_column = 0
|
470
345
|
|
471
346
|
preview_limit = None
|
472
347
|
|
473
348
|
handle_uploaded_files = None
|
474
|
-
"""
|
475
|
-
Handler for uploaded files.
|
476
|
-
Same remarks as for :attr:`lino.core.actors.Actor.disabled_fields`.
|
477
|
-
"""
|
478
|
-
|
479
349
|
default_record_id = None
|
480
|
-
"""
|
481
|
-
Turn this table into a :doc:`single-row table </topics/singlerow>`.
|
482
|
-
|
483
|
-
When this is not `None`, you must also implement a custom version of
|
484
|
-
:meth:`get_row_by_pk` that returns the same :term:`database row` regardless
|
485
|
-
the given :term:`primary key`.
|
486
|
-
|
487
|
-
This must currently be either `None` or ``'row'`` (or ``'myself'``).
|
488
|
-
|
489
|
-
TODO: Rename this to `single_row` and make it a simple boolean so that the
|
490
|
-
application developer can say ``single_row = True`` instead of
|
491
|
-
``default_record_id = 'row'``.
|
492
|
-
|
493
|
-
"""
|
494
350
|
|
495
351
|
def __init__(self, *args, **kw):
|
496
352
|
raise Exception("Actors should never get instantiated")
|
@@ -1682,11 +1538,6 @@ class Actor(Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
1682
1538
|
|
1683
1539
|
@classmethod
|
1684
1540
|
def get_toolbar_actions(self, parent, user_type):
|
1685
|
-
"""
|
1686
|
-
Return a list of actions for which a button should exist in the
|
1687
|
-
toolbar of the specified "parent" action.
|
1688
|
-
"""
|
1689
|
-
|
1690
1541
|
for ba in self.get_button_actions(parent):
|
1691
1542
|
if ba.action.show_in_toolbar and ba.get_view_permission(user_type):
|
1692
1543
|
if ba.action.readonly or not self.hide_editing(user_type):
|
@@ -1703,14 +1554,6 @@ class Actor(Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
1703
1554
|
|
1704
1555
|
@classmethod
|
1705
1556
|
def get_button_actions(self, parent):
|
1706
|
-
"""
|
1707
|
-
Return a sorted list of actions that should be available as
|
1708
|
-
buttons in the specified `parent` (a window action).
|
1709
|
-
|
1710
|
-
This is used (1) by :meth:`get_toolbar_actions` and (2) to
|
1711
|
-
reduce the list of disabled actions in `disabled_fields` to
|
1712
|
-
those which make sense. `dbtables.make_disabled_fields`
|
1713
|
-
"""
|
1714
1557
|
if not parent.opens_a_window:
|
1715
1558
|
# return []
|
1716
1559
|
raise Exception(
|
@@ -1720,9 +1563,6 @@ class Actor(Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
1720
1563
|
|
1721
1564
|
@classmethod
|
1722
1565
|
def get_actions(self):
|
1723
|
-
"""
|
1724
|
-
Return a sorted list of all bound actions offered by this actor.
|
1725
|
-
"""
|
1726
1566
|
return self._actions_list
|
1727
1567
|
|
1728
1568
|
@classmethod
|
lino/core/elems.py
CHANGED
@@ -1103,7 +1103,7 @@ class ForeignKeyElement(ComplexRemoteComboFieldElement):
|
|
1103
1103
|
if actor is None:
|
1104
1104
|
return kw
|
1105
1105
|
|
1106
|
-
if settings.SITE.kernel.
|
1106
|
+
if settings.SITE.kernel.editing_front_end.app_label == "react":
|
1107
1107
|
options = dict(
|
1108
1108
|
related_actor_id=actor.actor_id, allowBlank=kw.get(
|
1109
1109
|
"allowBlank", False)
|
lino/core/fields.py
CHANGED
lino/core/kernel.py
CHANGED
@@ -610,6 +610,7 @@ class Kernel(object):
|
|
610
610
|
# print("\n".join(["- {0.url_prefix} --> {0.app_name} {1}".format(p, hash(p))
|
611
611
|
# for p in self.web_front_ends]))
|
612
612
|
|
613
|
+
editing_wf = None
|
613
614
|
for p in self.web_front_ends:
|
614
615
|
if p.ui_handle_attr_name is not None:
|
615
616
|
editing_wf = p
|
@@ -686,6 +687,7 @@ class Kernel(object):
|
|
686
687
|
# trigger creation of params_layout.params_store and
|
687
688
|
# virtual fields in LightWeightContainer
|
688
689
|
for res in actors.actors_list:
|
690
|
+
field_actions = dict()
|
689
691
|
for ba in res.get_actions():
|
690
692
|
# ba._started = True
|
691
693
|
if ba.help_text is None:
|
@@ -694,6 +696,10 @@ class Kernel(object):
|
|
694
696
|
ba.action.params_layout.get_layout_handle()
|
695
697
|
if ba.action.is_window_action():
|
696
698
|
ba.get_layout_handel()
|
699
|
+
if ba.action.buddy_name:
|
700
|
+
lst = field_actions.setdefault(ba.action.buddy_name, [])
|
701
|
+
lst.append(ba)
|
702
|
+
res._field_actions = field_actions
|
697
703
|
|
698
704
|
# logger.info("20161219 kernel_startup done")
|
699
705
|
|
lino/core/layouts.py
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
"""
|
6
6
|
|
7
|
-
from lino import logger
|
8
7
|
import re
|
9
8
|
|
10
9
|
from django.conf import settings
|
@@ -14,6 +13,8 @@ from django.db.models.fields import NOT_PROVIDED
|
|
14
13
|
from django.db.models.fields.related import ForeignObject
|
15
14
|
# from django.contrib.contenttypes.fields import GenericRelation
|
16
15
|
|
16
|
+
from lino import logger
|
17
|
+
from lino.utils import jsgen
|
17
18
|
from lino.core import constants
|
18
19
|
from lino.core import atomizer
|
19
20
|
from lino.core import fields
|
@@ -222,6 +223,7 @@ class LayoutHandle:
|
|
222
223
|
if len(elems) == 1 and elemname != "main":
|
223
224
|
elems[0].setup(**kwargs)
|
224
225
|
return elems[0]
|
226
|
+
|
225
227
|
from lino.core.elems import create_layout_panel
|
226
228
|
|
227
229
|
return create_layout_panel(self, elemname, vertical, elems, **kwargs)
|
@@ -813,16 +815,12 @@ class ActionParamsLayout(ParamsLayout):
|
|
813
815
|
url_param_name = constants.URL_PARAM_FIELD_VALUES
|
814
816
|
|
815
817
|
def setup_element(self, lh, e):
|
816
|
-
from lino.utils import jsgen
|
817
|
-
|
818
818
|
e.declare_type = jsgen.DECLARE_THIS
|
819
819
|
|
820
820
|
def get_choices_url(self, ui, field, **kw):
|
821
|
-
return settings.SITE.kernel.
|
821
|
+
return settings.SITE.kernel.editing_front_end.build_plain_url(
|
822
822
|
"apchoices",
|
823
823
|
self._datasource.defining_actor.app_label,
|
824
824
|
self._datasource.defining_actor.__name__,
|
825
825
|
self._datasource.action_name,
|
826
|
-
field.name,
|
827
|
-
**kw,
|
828
|
-
)
|
826
|
+
field.name, **kw)
|
lino/core/model.py
CHANGED
lino/core/plugin.py
CHANGED
lino/core/renderer.py
CHANGED
@@ -498,7 +498,7 @@ class HtmlRenderer(Renderer):
|
|
498
498
|
return E.p(*buttons)
|
499
499
|
|
500
500
|
def get_home_url(self, *args, **kw):
|
501
|
-
return settings.SITE.kernel.
|
501
|
+
return settings.SITE.kernel.editing_front_end.build_plain_url(*args, **kw)
|
502
502
|
|
503
503
|
def obj2url(self, ar, obj):
|
504
504
|
ba = obj.get_detail_action(ar)
|
lino/core/requests.py
CHANGED
@@ -1842,10 +1842,9 @@ class ActionRequest(BaseRequest):
|
|
1842
1842
|
pv = self.actor.param_defaults(self)
|
1843
1843
|
for k in pv.keys():
|
1844
1844
|
if k not in self.actor.parameters:
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1848
|
-
)
|
1845
|
+
msg = f"{self.actor} param_defaults() returned keyword {k}"
|
1846
|
+
msg += f" (must be one of {sorted(self.actor.parameters.keys())})"
|
1847
|
+
raise Exception(msg)
|
1849
1848
|
|
1850
1849
|
# New since 20120913. E.g. newcomers.Newcomers is a
|
1851
1850
|
# simple pcsw.Clients with
|
lino/core/site.py
CHANGED
@@ -862,7 +862,7 @@ class Site(object):
|
|
862
862
|
needed_by = ip
|
863
863
|
# while needed_by.needed_by is not None:
|
864
864
|
# needed_by = needed_by.needed_by
|
865
|
-
for dep in ip.
|
865
|
+
for dep in ip.get_needed_plugins():
|
866
866
|
k2 = dep.rsplit(".")[-1]
|
867
867
|
if k2 not in self.plugins:
|
868
868
|
install_plugin(dep, needed_by=needed_by)
|
lino/core/utils.py
CHANGED
@@ -664,10 +664,11 @@ class Parametrizable:
|
|
664
664
|
parameters = None
|
665
665
|
params_layout = None
|
666
666
|
params_panel_hidden = True
|
667
|
-
params_panel_pos = "
|
667
|
+
params_panel_pos = "bottom" # allowed values "top", "bottom", "left" and "right"
|
668
668
|
use_detail_param_panel = False
|
669
669
|
|
670
670
|
_params_layout_class = NotImplementedError
|
671
|
+
_field_actions = dict()
|
671
672
|
|
672
673
|
def get_window_layout(self, actor):
|
673
674
|
return self.params_layout
|
@@ -1238,11 +1239,12 @@ def register_params(cls):
|
|
1238
1239
|
cls.params_layout = cls._params_layout_class.join_str.join(
|
1239
1240
|
cls.parameters.keys()
|
1240
1241
|
)
|
1242
|
+
if cls.params_layout is not None:
|
1241
1243
|
install_layout(cls, "params_layout", cls._params_layout_class)
|
1242
1244
|
|
1243
|
-
# e.g. accounting.ByJournal is just a mixin but provides a default value for its children
|
1244
|
-
elif cls.params_layout is not None:
|
1245
|
-
|
1245
|
+
# # e.g. accounting.ByJournal is just a mixin but provides a default value for its children
|
1246
|
+
# elif cls.params_layout is not None:
|
1247
|
+
# raise Exception("{} has a params_layout but no parameters".format(cls))
|
1246
1248
|
|
1247
1249
|
# if isinstance(cls, type) and cls.__name__.endswith("Users"):
|
1248
1250
|
# # if isinstance(cls, type) and cls.model is not None and cls.model.__name__ == "User":
|
lino/help_texts.py
CHANGED
@@ -312,7 +312,6 @@ help_texts = {
|
|
312
312
|
'lino.core.model.Model.create_from_choice' : _("""Called when a learning combo has been submitted. Create a persistent database object if the given text contains enough information."""),
|
313
313
|
'lino.core.model.Model.choice_text_to_dict' : _("""Return a dict of the fields to fill when the given text contains enough information for creating a new database object."""),
|
314
314
|
'lino.core.model.Model.allow_cascaded_delete' : _("""A set of names of ForeignKey or GenericForeignKey fields of this model that allow for cascaded delete."""),
|
315
|
-
'lino.core.model.Model.disabled_fields' : _("""Return a set of field names that should be disabled (i.e. not editable) for this database object."""),
|
316
315
|
'lino.core.model.Model.__str__' : _("""Return a translatable text that describes this database row."""),
|
317
316
|
'lino.core.model.Model.as_str' : _("""Return a translatable text that describes this database row. Unlike __str__() this method gets an action request when it is called, so it knows the context."""),
|
318
317
|
'lino.core.model.Model.get_str_words' : _("""Yield a series of words that describe this database row in plain text."""),
|
@@ -705,11 +704,13 @@ help_texts = {
|
|
705
704
|
'lino.modlib.weasyprint.WeasyHtmlBuildMethod' : _("""Renders the input template and returns the unmodified output as plain HTML."""),
|
706
705
|
'lino.modlib.weasyprint.WeasyPdfBuildMethod' : _("""Like WeasyBuildMethod, but the rendered HTML is then passed through weasyprint which converts from HTML to PDF."""),
|
707
706
|
'lino.core.model.Model' : _("""Lino extension of Django’s database model. This is a subclass of Django’s Model class (django.db.models.Model)."""),
|
707
|
+
'lino.core.model.Model.__init__' : _("""The first positional argument is the optional label, other arguments should be specified as keywords and can be any of the existing class attributes."""),
|
708
708
|
'lino.core.model.Model.overview' : _("""A multi-paragraph representation of this database row."""),
|
709
709
|
'lino.core.model.Model.navigation_panel' : _("""A virtual field that displays the navigation panel for this row. This may be included in a detail layout, usually either on the left or the right side with full height."""),
|
710
710
|
'lino.core.model.Model.workflow_buttons' : _("""Shows the current workflow state of this database row and a list of available workflow actions."""),
|
711
711
|
'lino.core.model.Model.workflow_state_field' : _("""Optional default value for the workflow_state_field of all data tables based on this model."""),
|
712
712
|
'lino.core.model.Model.workflow_owner_field' : _("""Optional default value for workflow_owner_field on all data tables based on this model."""),
|
713
|
+
'lino.core.model.Model.disabled_fields' : _("""Return a set of field names that should be disabled (i.e. not editable) for this database object."""),
|
713
714
|
'lino.core.model.Model.FOO_changed' : _("""Called when field FOO of an instance of this model has been modified through the user interface."""),
|
714
715
|
'lino.core.model.Model.FOO_choices' : _("""Return a queryset or list of allowed choices for field FOO."""),
|
715
716
|
'lino.core.model.Model.create_FOO_choice' : _("""For every field named “FOO” for which a chooser exists, if the model also has a method called “create_FOO_choice”, then this chooser will be a learning chooser. That is, users can enter text into the combobox, and Lino will create a new database object from it."""),
|
lino/mixins/registrable.py
CHANGED
@@ -118,12 +118,14 @@ class Registrable(model.Model):
|
|
118
118
|
# yield 'date'
|
119
119
|
|
120
120
|
def disabled_fields(self, ar):
|
121
|
+
rv = super().disabled_fields(ar)
|
121
122
|
if not self.state.is_editable:
|
122
123
|
# return self._registrable_fields
|
123
124
|
# Copy _registrable_fields otherwise _registrable_fields get
|
124
125
|
# modified as more disabled fields are added to the set.
|
125
|
-
return self._registrable_fields.copy()
|
126
|
-
|
126
|
+
# return self._registrable_fields.copy()
|
127
|
+
rv |= self._registrable_fields
|
128
|
+
return rv
|
127
129
|
|
128
130
|
def get_row_permission(self, ar, state, ba):
|
129
131
|
"""Only rows in an editable state may be edited.
|
lino/modlib/extjs/views.py
CHANGED
@@ -463,6 +463,13 @@ class ApiElement(View):
|
|
463
463
|
else:
|
464
464
|
datarec = ar.elem2rec_detailed(elem)
|
465
465
|
datarec.update(**vm)
|
466
|
+
|
467
|
+
fa = dict()
|
468
|
+
for k, lst in rpt._field_actions.items():
|
469
|
+
fa[k] = [ar.row_action_button(elem, ba) for ba in lst]
|
470
|
+
if fa:
|
471
|
+
datarec.update(field_actions=fa)
|
472
|
+
|
466
473
|
return json_response(datarec)
|
467
474
|
|
468
475
|
after_show = ar.get_status(record_id=pk)
|
lino/modlib/linod/__init__.py
CHANGED
@@ -50,7 +50,7 @@ class Plugin(ad.Plugin):
|
|
50
50
|
m = m.add_menu(mg.app_label, mg.verbose_name)
|
51
51
|
m.add_action("linod.Procedures")
|
52
52
|
|
53
|
-
def
|
53
|
+
def get_needed_plugins(self):
|
54
54
|
# We don't use needs_plugins because it depends on use_channels. We must
|
55
55
|
# not install the plugin when the Python package isn't installed because
|
56
56
|
# otherwise `pm install` fails with ModuleNotFoundError: No module named
|
lino/modlib/memo/__init__.py
CHANGED
@@ -50,7 +50,7 @@ class Plugin(ad.Plugin):
|
|
50
50
|
"""The front end to use when writing previews.
|
51
51
|
|
52
52
|
If this is `None`, Lino will use the default :term:`front end`
|
53
|
-
(:attr:`lino.core.site.Site.
|
53
|
+
(:attr:`lino.core.site.Site.editing_front_end`).
|
54
54
|
|
55
55
|
Used on sites that are available through more than one web front ends. The
|
56
56
|
:term:`server administrator` must then decide which front end is the primary
|
@@ -115,7 +115,6 @@ class Plugin(ad.Plugin):
|
|
115
115
|
def post_site_startup(self, site):
|
116
116
|
if self.front_end is None:
|
117
117
|
self.front_end = site.kernel.editing_front_end
|
118
|
-
# web_front_ends[0]
|
119
118
|
else:
|
120
119
|
self.front_end = site.plugins.resolve(self.front_end)
|
121
120
|
|
lino/modlib/office/roles.py
CHANGED
lino/modlib/printing/actions.py
CHANGED
@@ -294,19 +294,15 @@ class EditTemplate(BasePrintAction):
|
|
294
294
|
ar.confirm(ok, msg, _("Are you sure?"))
|
295
295
|
|
296
296
|
|
297
|
-
class
|
297
|
+
class ClearCache(Action):
|
298
298
|
sort_index = 51
|
299
299
|
url_action_name = "clear"
|
300
300
|
label = _("Clear cache")
|
301
301
|
icon_name = "printer_delete"
|
302
302
|
|
303
|
-
# def disabled_for(self,obj,request):
|
304
|
-
# if not obj.build_time:
|
305
|
-
# return True
|
306
|
-
|
307
303
|
def get_action_permission(self, ar, obj, state):
|
308
304
|
# obj may be None when Lino asks whether this action
|
309
|
-
# should be visible in the
|
305
|
+
# should be visible in the table toolbar
|
310
306
|
if obj is not None and not obj.build_time:
|
311
307
|
return False
|
312
308
|
return super().get_action_permission(ar, obj, state)
|