[Freeipa-devel] Nesting widgets

Endi Sukma Dewata edewata at redhat.com
Wed Nov 2 01:11:53 UTC 2011


>  >>> So I decided to try to get an IP Address widget working. See the
>  >>> attached patch. It was fairly trivial.
>  >>>
>  >>> However, this widget is not really all that useful by itself. It would
>  >>> need to work as a part of a multivalued_text widget in order to
> replace
>  >>> the widget used on the dnsrecord page. And looking at the multivalued
>  >>> text widget, I think you will agree that is going to be tricky.
>  >>
>  >> I think we can create an extend point for validation logic (EG
>  >> validator object in field's spec) instead of inheriting the widget.

To summarize the recent discussion on IRC and other threads, we're 
planning to split the existing widget concept into (logical) fields and 
(visual) widgets. See: https://fedorahosted.org/freeipa/ticket/2040

The new widgets will be used mainly for input/output like the existing 
widgets, but they can also be any other UI components such as header or 
separator.

The widgets will support nesting. For example, the multivalued widget 
will become a composite widget which has an Add and Undo All links and 
can contain other widgets:

   widgets: [
       {
           factory: IPA.multivalued_widget,
           name: 'fullName',
           widget: IPA.text_widget
       }
   ]

The widgets can be arranged inside a section, which is also a composite 
widget that has a header and is collapsible.

   widgets: [
       {
           factory: IPA.section_widget,
           name: 'identity',
           widgets: [
               {
                   factory: IPA.text_widget,
                   name: 'fullName'
               }
           ]
       }
   ]

For IP address we could either use a text widget with an IP address 
validator, or we could also implement a custom IP address widget. Either 
solution can be used inside multivalued widget.

   widgets: [
       {
           factory: IPA.multivalued_widget,
           name: 'ipaddress1',
           widget: {
               factory: IPA.text_widget,
               validator: IPA.ipaddress_validator
           }
       },
       {
           factory: IPA.multivalued_widget,
           name: 'ipaddress2',
           widget: IPA.ipaddress_widget,
       },
   ]

>  > Interesting concept. Yes, this would work too, and solve the issue for
>  > IP addresses validation. But there are places where we may want to
>  > validate only a single IP address, and we may end up with code
>  > duplication, although more likely they will both just call the same
>  > utility function.

Since the multivalued widget is completely separate, we can reuse the IP 
address widget for a single valued attribute.

   widgets: [
       {
           factory: IPA.ipaddress_widget,
           name: 'ipaddress'
       }
   ]

>  >>> In order to make the widget scheme more nestable, the section
>  >>> section.load and save can do more work, such as scoping down the piece
>  >>> of the request record to just that portion required by the widget.
>  >>> Bascially, it can do what widget.load does, just externally
>  >>
>  >> I don't think this would help. This would limit the widget. Currently
>  >> most widget works with the record.[widget name]. But we can override
>  >> load and save method to break the 1:1 mapping between widget and
>  >> record. Widget can consist of several widgets and supply them custom
>  >> record object (it can assume that the simple widget would fetch the
>  >> value of its name. The name is defined by the master widget (no
>  >> problem here).)
>  >>
>  >> The concept you mentioned could be beneficial if we abandon flat
>  >> records and introduce structured ones. But I think there is no will
>  >> for it. Event then I don't know if sections should be responsible for
>  >> this. It's not their purpose.
>  >
>  > Records are already structured, just that by the time we get to the
>  > individual fields, they tend to be flat. But the record is JSON and is a
>  > tree structure.
>  >
>  > But I like what you are saying. I agree that the interface for Widget
>  > and Section should be the same. Right now Section is:
>  > that.save = function(record) {};
>  > that.load = function(record) {);
>  >
>  > and load is
>  > that.load = function(record) {};
>  > that.save = function() {};
>  >
>  > It is this last function that needs to be changed, but it will have far
>  > reaching effects. We use save to extract the value or values from the
>  > field for many uses. I think we can do this: For all widgets, rename
>  > save() to get_value(); and then add a save(record) method that calls
>  > get_value(); Then widget and record have the same interface, which is a
>  > big first step.

The fields will be used to load/store attributes. Each field usually 
will have a corresponding widget, except hidden fields:

   fields: [
       {
           name: 'krbprincipalname' // hidden
       },
       {
           name: 'cn',
           widget: 'identity.fullName' // widget inside a section
       },
       {
           name: 'mail',
           widget: 'contact.email' // multivalued widget
       }
   ]

During load the fields will be used to get the attributes from the 
records returned by the server and then pass them to the corresponding 
widgets to be displayed.

During update the fields will be used to save the values from the 
corresponding widgets and they will be used to generate the update 
commands. This will be covered in this ticket:
https://fedorahosted.org/freeipa/ticket/2041

We might be able to do nested fields too to handle hierarchical records, 
but that's not needed now.

>  >> Another (maybe bigger) problem is layout. For multivalued textbox with
>  >> IP address widget one of the problems can be the placement (or even
>  >> behaviour) of 'undo' and 'error-link'. Possible solution could be:
>  >> specifying container for these parts by its container - the containing
>  >> widget could control where they would be rendered. Another one can be
>  >> API notification of the state change (no visual by the widget itself)
>  >> and handling it by the parent widget.
>  >>
>  >> For more layout demanding widgets section layout can be limiting (like
>  >> in host adder dialog which force to implement custom section instead
>  >> of widget). Which in my opinion is bad, but we don't have any other
>  >> solution for this yet. I think there is a ticket for it.
>  >
>  > Perhaps for more complex widgets, we can extract the layout into its own
>  > object, and pass it to the constructore. We'll provide one by default,
>  > but allow overloading.

Yes, by default all containers (facets, dialogs, or composite widgets) 
will use 1-column layout. So the nested widgets will be arranged 
vertically with the same width. Each widget will be able to implement 
custom layout. This is probably sufficient for now. See also:
https://fedorahosted.org/freeipa/ticket/1501

Other related tickets:
https://fedorahosted.org/freeipa/ticket/2042
https://fedorahosted.org/freeipa/ticket/2043
https://fedorahosted.org/freeipa/ticket/2052

-- 
Endi S. Dewata




More information about the Freeipa-devel mailing list