LuCI: Auto create section if does not exists and reuse existing

I would like to implement my custom luci application (in javascript) to configure existing service.
The reason is, that original LuCI configuration page is overcomplicated for my purpose.

Problem is, that the configuration has sections which are not always present.

Using this construct,

s = m.section(form.TypedSection, "my-section");
s.addremove = true;

I can create section on demand, but it adds ugly add/remove buttons and it is also possible to completely remove the section which I don't want.

s.addremove = false;

just displays that there is no suitable section.

Is there some hack, I can persuade LuCI that the section exists even if it does not, so it will alwasy display exactly one form for my section without add/remove buttons?

I was thingking about load() hook, but I don't know how to use it for this purpose.

Finally got it working. uci.load must be called prior uci.get.
If the section is anonymouse, it can't be get just by type name like in form.TypedSection but by index so mysection becoms @mysection[0].
Then, the condition with uci.get finally works so I can add missing section, if it does not exists.

I just still don't understand why this is not the default behavior for anonymouse=true and addremove=false sections so this ugly hack is necesery.

Minimal example:

'use strict';
'require form';
'require view';
'require uci';

return view.extend({
    load: function () {
        return uci.load('myconfig');
    },

    render: function () {
        let m, s, o;

        m = new form.Map("myconfig", _("Configuration of my thing"));
       
        if (uci.get(m.config, "@mysection[0]") == null) {
            m.data.add(m.config, "mysection");
        }
        
        s = m.section(form.TypedSection, "mysection");
        s.addremove = false;
        s.anonymous = true;

        o = s.option(form.Flag, "enabled", _('Enable'));
        o.default = false;

        return m.render();
    }
});

Because we don't want to trigger configuration changes by merely rendering the form without further interaction. If at all, then we'd want some kind of auto-create-on-save behavior but that would be more complex to implement.

You should be able to overwrite the default cfgsections() implementation with a custom function that returns a one element array with a fake section ID (like '__new__') in case there is no existing section yet. Then overwrite the parse() method with some logic that will auto create the section on demand.

Example (untested):

// ...

var s = m.section(form.TypedSection, ...);

// ...

s.cfgsections = function() {
    var section_ids = form.TypedSection.prototype.cfgsections.apply(this);
    return section_ids.length ? section_ids : [ '__new__' ];
};

s.parse = function() {
    var section_ids = this.cfgsections();

    if (section_ids.length == 1 && section_ids[0] == '__new__')
        this.map.data.add(this.uciconfig || this.map.config, this.sectiontype /*, 'optional_fixed_name' */);

    return form.TypedSection.prototype.parse.apply(this);
};

Edit: theoretically it is possible for a user to create a valid uci section called __new__ which would trip up the logic above. To be 100% correct you should chose a name that cannot appear in a valid configuration, like .new or #create.

1 Like

This is interesting. I must try it soon. This means that I can end with more generic custom type derived from form.TypedSection and not copy/paste my ugly solution.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.