Saturday, September 9, 2017

A new way for disabling actions per row

It is now possible to disable an action by adding its name to the set returned by disabled_fields.

This approach can be more intuitive to write and less costly to run. For example the three actions on lino_xl.lib.stars.Starrable are now implemented using this new possibility.

Here is a fictive example

  1. Using get_action_permission method of the action:

    class DoOne(dd.Action):
        ...
        def get_action_permission(self, ar, obj, st):
            for x in obj.foos.all():
                if x.bar:
                    return False
            return super(DoOne, self).get_action_permission(ar, obj, st)
    
    class Foo(dd.Model):
        do_one = DoOne()
    
  2. Using the disabled_fields method of the model which defines the action:

    class DoOne(dd.Action):
        ...
        # no get_action_permission()
    
    class Foo(dd.Model):
    
        do_one = DoOne()
    
        def disabled_fields(self, ar):
            s = super(Foo, self).disabled_fields(ar)
            for x in self.foos.all():
                if x.bar:
                    s.add("do_one")
            return s
    

No more method disabled_actions : actions share the same namespace as fields, so there was no need to separate them. A side effect of this is that in readonly tables it is no longer possible to disable individual actions. Which AFAICS is correct.

In linoweb.js, I replaced “disabled_actions” by “disabled_fields”. For example:

var da = record.data.disabled_actions;

becomes:

var da = record.data.disabled_fields;

One challenge were actions with an allowed_states. These are now handled more efficiently. Lino analyses the situation once at startup and creates per actor a dict _state_to_disabled_actions which is then being used for disabling these actions based on the row’s state.