Disable elements of the user interface¶
Lino provides several methods to customize whether data is editable or not.
Disable individual fields¶
Sometimes you want to disable (make non-editable) individual fields of a form based on certain conditions. The conditions for disabling individual fields can be application specific and based e.g. on user roles or the values of certain other fields of the object being displayed.
For example, in Lino Così an invoice disables most fields when it has been registered. Here are two screenshots of a same invoice, once when the invoice's state is "draft" and once when it is "registered":
In Lino you define this behaviour by overriding the
disabled_fields instance method on your model.
- class lino.core.model.Model
Here is a fictive example:
class MyModel(dd.Model): ... def disabled_fields(self, ar): s = super(MyModel, self).disabled_fields(ar) ... return set()
Invoice model used in above screenshots does something
class Invoice(dd.Model): ... def disabled_fields(self, ar): df = super(Invoice, self).disabled_fields(ar) if self.state == InvoiceStates.registered: df.add('subject') df.add('payment_term') ... return df
The decision which fields to disable may depend an the current user. Here is a
fictive example of a model
Case where only the author may change first
and last name:
class Case(dd.Model): ... def disabled_fields(self, ar): df = super(Case, self).disabled_fields(ar) if self.author == ar.get_user(): return df df.add('first_name') df.add('last_name') return df
You may want to override this method on the actor instead of per model. In that case it must be a classmethod with two arguments obj and ar:
@classmethod def disabled_fields(cls, obj, ar): s = super(MyActor, cls).disabled_fields(obj, ar) ... return set()
You may also disable actions simply by adding their name to the set returned
disabled_fields. (The method
disabled_fields() is actually misleading, one day we might rename it
Disable editing of a whole table¶
In some data windows you may want to disable editing functionality altogether.
lino.modlib.checkdata.Problems. You don't want to modify them, nor
delete them, not create new rows in these data windows. Not even when you are a
You do this by setting
Actor.editable to False. This will remove
editing functionality for everybody.
Disable editing of a whole table¶
In other cases you want to remove editing functionality only for certain user
types. You do this by overriding the
Actor.hide_editing() method. For
lino_xl.lib.products.Products says that ProductsUser can see
products, but only ProductsStaff can edit them:
class Products(dd.Table): required_roles = dd.login_required(ProductsUser) @classmethod def hide_editing(cls, user_type): if user_type is not None: if not user_type.has_required_roles([ProductsStaff]): return True return super(Products, cls).hide_editing(user_type)
- class lino.core.actors.Actor
Whether a data window on this actor is editable.
The front end uses this information to generate optimized JS code for these actors.
Set this explicitly to True or False to make the whole actor editable or not. Otherwise Lino will guess what you want during startup and set it to False if the actor is a Table and has a get_data_rows method (which usually means that it is a virtual table), otherwise to True.
This attribute is not inherited to subclasses.
Actors with a modified toolbar¶
hide_top_toolbar attribute changes the
toolbar (1) to be at the bottom of the window instead of the top and (2) to have
only actor-specific actions, i.e. no navigation buttons, no refresh button, no
class SiteConfigs(dd.Table): hide_top_toolbar = True
(TODO: rename it to something else.)