On 10/27/2011 05:51 PM, Endi Sukma Dewata wrote:
On 10/27/2011 8:39 AM, Petr Vobornik wrote:
But still I think it would be better to be able to get container
(facet/dialog) for a widget. As you wrote, that.entity.get_facet() may
not always be what we want.

One possibility is to convert the facet & dialog into subclasses of an abstract container class. The container needs to provide functions such as refresh() so the widget doesn't need to know whether it's a facet or dialog.

Btw similar topic could be: "How to get current entity's pkey?'.
Dependancy on facet.get_primary_key() or
IPA.nav.get_state(that.entity.name+'-pkey') seems wrong too.

Yes. Ideally we should have a path (REST-style URL) instead of the
current parameter-based URL. We should get the pkey from that path.

 From dependency point of view, widgets would be still dependant on the
implementation of navigation (IMHO bad).

But it seems that using entity.get_primary key partially solves the
problem.



It could be argued that since this is a web app everything will have a path, but for now getting primary key from entity is fine since everything also has an associated entity.

Maybe it would be better if navigation would inject pkey to entity.
Entity wouldn't be that much dependant on navigation implementation.

We might need to distinguish 2 different usages of 'entity'. The first one represents a collection of entries:

Call that an instance.  Entity is the  term that is the analogue of  Class

So we want to distinguish getting the primary key field for the entity, as opposed to the primary key of the instance.


  var users = IPA.get_entity('user');
  users.add([ 'test' ], { givenName: 'Test', ... });
  var result = users.find('t*');

The second one represents individual entry:

  var user = result.result[0];
  user.update({ sn: 'User' });

The entity collection should be 'stateless', it will be used in search pages. The individual entity will be 'stateful', it contains the pkey and the values of its attributes, and it will be used in the details page.

The entity.get_primary_key() is an interface to get the primary keys for a particular entity from the current path. So when you open a URL for an entry's details facet, it will execute the following command:

  var pkeys = entity.get_primary_key();
  var object = entity.get(pkeys);

Then the facet will use the object to populate the page.

The priority could be part of update info. As there is a field_info we
can create a command_info: { command, priority }.

I'm a little unclear on the usage of priority.

Before adding commands to batch_command, array of command_info objects
would joined with 'mod' command with default priority and then sorted by
priority.

If the priority was set on each widget, priority management will be on
facet level, which may be fine. There can be some corner case like
dynamic change of priority.

I'd have to see how it's implemented.

One other solution is to split widgets into non-visual fields and purely
HTML components. Then in the facet we use separate lists for the fields
and HTML components. The fields will have a reference to the
corresponding HTML components. There can be more HTML components than
fields. But this will require a significant restructuring.

Maybe we can use hybrid solution: html widgets would be simple object
with some properties and create() method. They should not be called
widgets. They would not be part of sections fields. Rendering would be
done in widgets/sections create() method (as it is now).

I think this is not quite right. Widget is just a generic term for an element of the UI object model. It is intentionally generic. A Widget can be just about anything. Some bind down to the individual fields, or in somcses, even smaller, but widget could easily be the base class for Facets, sections and the widget we have now.


I'm not very clear, we could be talking about the same thing. The (non-HTML) fields could be defined like this:

  fields: [
      {
          name: 'cn',
          widget: 'identity.cn'
      },
      {
          name: 'email',
          widget: 'identity.email'
      },
      {
          factory: IPA.password_field,
          name: 'userpassword',
          widgets: [ 'account.password1', 'account.password2' ]
      }
  ]

The specs above will be used to create IPA.field objects (not widget) to assist loading/saving attributes. Then we could also define the HTML components (let's call it widget) separately:

  widgets: [
      {
          factory: IPA.table_section,
          name: 'identity',
          label: 'Identity'
          widgets: [
              {
                  factory: IPA.text_widget,
                  name: 'cn'
              },
              {
                  factory: IPA.multivalued_widget,
                  name: 'email',
                  widget: IPA.text_widget
              }
          ]
      }
  ]

The specs above will be used to create IPA.widget objects to generate the HTML content. If there is no widget specs specified, we could generate it automatically from the field specs.

Pros:
- reusable layouts, headers...
- not polluting field names
Cons:
- not so declarative - need to override update method, create custom
section/widget factories - same as now

The above example should be quite declarative.

Question:
- what with widget nesting? rule_details_section is in fact a composite
widget. I would like to keep the concept, because it offers better code
reuse.

As shown above, widget (not field) nesting is possible.

A section is a composite widget with a specific layout: it has a header, it's collapsible, and it has nested widgets.

A table section is a section that uses 2 columns to display the nested widgets: one for the field label and the other for the widget itself.

A multivalued widget is a composite widget with one type of nested widgets and it has an Add and Undo All links.

The rule_details_section is a section with radio buttons (for the category) and some tables.

I think the decision to use mod or batch should be separate from details
facet. I'm thinking to create a separate class IPA.client which we can
add commands into it and execute them either individually or as a batch.

What would be the IPA.client's responsibilities? It'll be only a
container for commands with different executing strategies?

The IPA.client will represent a connection to the IPA server. In a browser IPA.client can only connect to the server it's loaded from:


  var client = IPA.client();

but in a JS engine like Rhino the IPA.client can connect to any IPA server:

   var client = IPA.client('ipa.example.com');

This will work now, but you will not be able to see the results of the command. Integrations like this are how the Like buttons from Facebook work. Cross site posting is tricky, but permitted, and might be useful in some cases. Possibly we should call it connection.

The IPA.client can be used to execute commands:

   var command = IPA.command(...);
   client.execute(command);

or start a batch:

   client.start_batch();
   client.execute(command1);
   client.execute(command2);
   client.end_batch();

or get the entities:

   var users = client.get_entity('user');


_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to