The effort was split to two patches. See patch descriptions.

Notes:
Case #7 (automatic: an open facet should automatically refresh itself when it expires) I don't want to implement because I think it can cause havoc ie: refresh when user is editing.

Also I was thinking about splitting needs_update to two methods: needs_update and state_changed. State changed would compare current state with old state. It would be called from needs_update. This way we don't have to override needs_update and just define various state_changed for different facets. Also I'm thinking about adding paging state comparison to search facet (the page should recognize the change itself ie when other facet redirects to certain page (bad example?)). What do you think?

https://fedorahosted.org/freeipa/ticket/2075
--
Petr Vobornik
From edcf372f0527b2ec0fea6edc03901cbcd212a320 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Thu, 22 Mar 2012 17:03:57 +0100
Subject: [PATCH] Facet expiration flag

Problem:

For performance reason a facet may cache the data in browser's memory. There should be a flag to indicate whether a facet has expired and should be refreshed. The expired flag could be set by these events:

 1) any update operation
 2) changing search filter in search facet
 3) switching page in a multi-paged search/association facet
 4) switching direct/indirect view in association facet
 5) facet expiration time
A facet should be able to use these methods to refresh itself:
 6) on demand: an expired facet should be refreshed when a user opens it.
 7) automatic: an open facet should automatically refresh itself when it expires.

Solution:

This patch solves cases: #2, #3, #5, #6. Case #4 works without any change. Case #1 will be solved later. Case #7 is deffered.

Default expiration timeout was set to 10 minutes.

In this patch are also updated facet.needs_update methods to reflect changes in containing facets.

https://fedorahosted.org/freeipa/ticket/2075
---
 install/ui/association.js |    4 +---
 install/ui/details.js     |   10 +++++++++-
 install/ui/facet.js       |   37 ++++++++++++++++++++++++++++++++++++-
 install/ui/ipa.js         |   15 +++++++++++++++
 install/ui/search.js      |   43 +++++++++++++++++++++++++++++++------------
 5 files changed, 92 insertions(+), 17 deletions(-)

diff --git a/install/ui/association.js b/install/ui/association.js
index 238006f4207ba3b3c9dda41d970c9d5d7d9277db..ab43518f68ee3e313e801ca695ca047fca953624 100644
--- a/install/ui/association.js
+++ b/install/ui/association.js
@@ -1064,9 +1064,7 @@ IPA.association_facet = function (spec) {
         var page = parseInt(IPA.nav.get_state(that.entity.name+'-page'), 10) || 1;
         if (that.table.current_page !== page) return true;
 
-        if (that.error_displayed()) return true;
-
-        return false;
+        return that.facet_needs_update();
     };
 
     init();
diff --git a/install/ui/details.js b/install/ui/details.js
index 32ace398fac2e5957fdc657f88121673e0b66210..f7e95ebfe296bda1a27de9195fb277c7693bc8e4 100644
--- a/install/ui/details.js
+++ b/install/ui/details.js
@@ -413,14 +413,21 @@ IPA.details_facet = function(spec) {
         that.facet_show();
 
         that.pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+        that.old_key_prefix = that.entity.get_primary_key_prefix();
         that.header.set_pkey(that.pkey);
     };
 
     that.needs_update = function() {
         if (that._needs_update !== undefined) return that._needs_update;
+
+        var needs_update = that.facet_needs_update();
+
         var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
-        var needs_update = that.error_displayed();
+        var key_prefix = that.entity.get_primary_key_prefix();
+
         needs_update = needs_update || pkey !== that.pkey;
+        needs_update = needs_update || IPA.array_diff(key_prefix, that.old_key_prefix);
+
         return needs_update;
     };
 
@@ -472,6 +479,7 @@ IPA.details_facet = function(spec) {
         }
         that.policies.post_load(data);
         that.enable_update(false);
+        that.clear_expired_flag();
     };
 
     that.save = function(record) {
diff --git a/install/ui/facet.js b/install/ui/facet.js
index ab71f820ff872d4a3607f5ee9fce8f2038ddfec8..a38bcddfa99bb2ad2dfe96512b9f058193fdbc2a 100644
--- a/install/ui/facet.js
+++ b/install/ui/facet.js
@@ -45,6 +45,9 @@ IPA.facet = function(spec) {
     that.header = spec.header || IPA.facet_header({ facet: that });
 
     that._needs_update = spec.needs_update;
+    that.expired_flag = true;
+    that.last_updated = null;
+    that.expire_timeout = spec.expire_timeout || 600; //[seconds]
 
     that.dialogs = $.ordered_map();
 
@@ -140,8 +143,34 @@ IPA.facet = function(spec) {
     };
 
     that.needs_update = function() {
+
         if (that._needs_update !== undefined) return that._needs_update;
-        return true;
+
+        var needs_update = false;
+
+        if (that.expire_timeout && that.expire_timeout > 0) {
+
+            if (!that.last_updated) {
+                needs_update = true;
+            } else {
+                var now = Date.now();
+                needs_update = (now - that.last_updated) > that.expire_timeout * 1000;
+            }
+        }
+
+        needs_update = needs_update || that.expired_flag;
+        needs_update = needs_update || that.error_displayed();
+
+        return needs_update;
+    };
+
+    that.set_expired_flag = function() {
+        that.expired_flag = true;
+    };
+
+    that.clear_expired_flag = function() {
+        that.expired_flag = false;
+        that.last_updated = Date.now();
     };
 
     that.is_dirty = function() {
@@ -263,6 +292,7 @@ IPA.facet = function(spec) {
     that.facet_create = that.create;
     that.facet_create_header = that.create_header;
     that.facet_create_content = that.create_content;
+    that.facet_needs_update = that.needs_update;
     that.facet_show = that.show;
     that.facet_hide = that.hide;
     that.facet_load = that.load;
@@ -583,6 +613,8 @@ IPA.table_facet = function(spec) {
         that.table.total_pages_span.text(that.table.total_pages);
 
         that.table.pagination_control.css('visibility', 'visible');
+
+        that.clear_expired_flag();
     };
 
 
@@ -821,6 +853,7 @@ IPA.table_facet = function(spec) {
             if (that.table.current_page > 1) {
                 var state = {};
                 state[that.entity.name+'-page'] = that.table.current_page - 1;
+                that.set_expired_flag();
                 IPA.nav.push_state(state);
             }
         };
@@ -829,6 +862,7 @@ IPA.table_facet = function(spec) {
             if (that.table.current_page < that.table.total_pages) {
                 var state = {};
                 state[that.entity.name+'-page'] = that.table.current_page + 1;
+                that.set_expired_flag();
                 IPA.nav.push_state(state);
             }
         };
@@ -841,6 +875,7 @@ IPA.table_facet = function(spec) {
             }
             var state = {};
             state[that.entity.name+'-page'] = page;
+            that.set_expired_flag();
             IPA.nav.push_state(state);
         };
     };
diff --git a/install/ui/ipa.js b/install/ui/ipa.js
index 34174c81a9b3fd142301c3ea80b86fb4e98a949f..be87481018654c6803b9c610df3723566a4efac2 100644
--- a/install/ui/ipa.js
+++ b/install/ui/ipa.js
@@ -1548,6 +1548,21 @@ IPA.is_empty = function(value) {
     return empty;
 };
 
+IPA.array_diff = function(a, b) {
+
+    if (a === b || (!a && !b)) return false;
+
+    if (!a || !b) return true;
+
+    if (a.length !== b.length) return true;
+
+    for (var i=0; i<a.length; i++) {
+        if (a[i] !== b[i]) return true;
+    }
+
+    return false;
+};
+
 IPA.config = {
     default_priority: 500
 };
diff --git a/install/ui/search.js b/install/ui/search.js
index 6bde398be12d27f5c1a441e91cbd2b2b85b35b40..b7c5034ab05dd101cd01aadd5c0490512ea8b8b9 100644
--- a/install/ui/search.js
+++ b/install/ui/search.js
@@ -4,6 +4,7 @@
  *    Pavel Zuna <pz...@redhat.com>
  *    Adam Young <ayo...@redhat.com>
  *    Endi S. Dewata <edew...@redhat.com>
+ *    Petr Vobornik <pvobo...@redhat.com>
  *
  * Copyright (C) 2010 Red Hat
  * see file 'COPYING' for use and warranty information
@@ -128,12 +129,25 @@ IPA.search_facet = function(spec) {
 
         var filter = IPA.nav.get_state(that.entity.name+'-filter');
         that.old_filter = filter || '';
+        that.old_pkeys = that.managed_entity.get_primary_key_prefix();
 
         if (that.filter) {
             that.filter.val(filter);
         }
     };
 
+    that.needs_update = function() {
+        if (that._needs_update !== undefined) return that._needs_update;
+
+        var needs_update = that.facet_needs_update();
+
+        //check if state changed
+        var pkeys = that.managed_entity.get_primary_key_prefix();
+        needs_update = needs_update || IPA.array_diff(pkeys, that.old_pkeys);
+
+        return needs_update;
+    };
+
     that.show_add_dialog = function() {
         var dialog = that.managed_entity.get_dialog('add');
         dialog.open(that.container);
@@ -171,8 +185,12 @@ IPA.search_facet = function(spec) {
 
     that.find = function() {
         var filter = that.filter.val();
+        var old_filter = IPA.nav.get_state(that.managed_entity.name+'-filter');
         var state = {};
         state[that.managed_entity.name + '-filter'] = filter;
+
+        if (filter !== old_filter) that.set_expired_flag();
+
         IPA.nav.push_state(state);
     };
 
@@ -186,16 +204,8 @@ IPA.search_facet = function(spec) {
 
     that.create_refresh_command = function() {
 
-        var filter = [];
-        var entity = that.managed_entity;
-
-        filter.unshift(IPA.nav.get_state(entity.name+'-filter'));
-        entity = entity.get_containing_entity();
-
-        while (entity !== null) {
-            filter.unshift(IPA.nav.get_state(entity.name+'-pkey'));
-            entity = entity.get_containing_entity();
-        }
+        var filter = that.managed_entity.get_primary_key_prefix();
+        filter.push(IPA.nav.get_state(that.managed_entity.name+'-filter'));
 
         var command = IPA.command({
             name: that.get_search_command_name(),
@@ -239,8 +249,14 @@ IPA.search_facet = function(spec) {
     };
 
     that.needs_clear = function() {
+        var clear = false;
         var filter = IPA.nav.get_state(that.entity.name+'-filter') || '';
-        return that.old_filter !== '' || that.old_filter !== filter;
+        clear = that.old_filter !== '' || that.old_filter !== filter;
+
+        var pkeys = that.managed_entity.get_primary_key_prefix();
+        clear = clear || IPA.array_diff(pkeys, that.old_pkeys);
+
+        return clear;
     };
 
     init();
@@ -337,8 +353,11 @@ IPA.nested_search_facet = function(spec) {
         that.header.set_pkey(
             IPA.nav.get_state(IPA.current_entity.name+'-pkey'));
 
+        var filter = IPA.nav.get_state(that.managed_entity.name+'-filter');
+        that.old_filter = filter || '';
+        that.old_pkeys = that.managed_entity.get_primary_key_prefix();
+
         if (that.filter) {
-            var filter = IPA.nav.get_state(that.managed_entity.name+'-filter');
             that.filter.val(filter);
         }
     };
-- 
1.7.7.6

From 4fc3c74669f0206cd898d77e37c8e00f4774f0bf Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Thu, 22 Mar 2012 17:31:48 +0100
Subject: [PATCH] Inter-facet expiration

Problem:

When some facet perform action which modifies data, some other facet may become expired.

Example: User modifies group's description. Now group search facet contains old data and has to be refreshed.

Solution:

New event was added to facet: on_update. It should be executed when facet performs action which modifies data ie: details facet update or add entry to dnsrecord.

Then entity policies were introduced. Entity policies are a objects which are stored in entity.policies. They have similar function as facet_policies - performing communications and other functionality between facets. This way facets don't have to contain such logic and thus they aren't dependant on each other.

This patch adds IPA.facet_update_policy, IPA.adder_facet_update_policy, IPA.search_facet_update_policy, IPA.details_facet_update_policy.

IPA.facet_update_policy: On facets_created it bind itself to [current entity].[source facet].[event]. Default event is on_update. When the event is executed it sets expiration flag to [dest entity].[dest facet].

IPA.search_facet_update_policy: IPA.facet_update_policy where source facet = search, dest facet = details, dest entity = current entity. Its a default policy for updatein changes from search facet to details facet. Right now it isn't needed but it will be needed when action lists come to play.

IPA.details_facet_update_policy: same as IPA.search_facet_update_policy just reversed. Very important.

IPA.adder_facet_update_policy: similar functionality, just source of the event is dialog. Default event is added (new event in entity_adder_dialog).

Entity policies should be specified in entity's spec object. If none are specified a default ones are used. Default policies are: IPA.search_facet_update_policy and IPA.details_facet_update_policy.

https://fedorahosted.org/freeipa/ticket/2075
---
 install/ui/add.js        |    4 +
 install/ui/automember.js |   13 ++++
 install/ui/automount.js  |   10 +++
 install/ui/details.js    |    1 +
 install/ui/dns.js        |   21 +++++++
 install/ui/entity.js     |  151 ++++++++++++++++++++++++++++++++++++++++++++++
 install/ui/facet.js      |    1 +
 install/ui/hbac.js       |    1 +
 install/ui/selinux.js    |    1 +
 install/ui/sudo.js       |    1 +
 10 files changed, 204 insertions(+), 0 deletions(-)

diff --git a/install/ui/add.js b/install/ui/add.js
index 671d3f1fcbd3c9be195db8d102a6d6c80bb5c041..a9969a5cbd1f3c6c29c9faf2467bc3566d6ca3cb 100644
--- a/install/ui/add.js
+++ b/install/ui/add.js
@@ -33,6 +33,7 @@ IPA.entity_adder_dialog = function(spec) {
     that.on_error = spec.on_error ;
     that.retry = typeof spec.retry !== 'undefined' ? spec.retry : true;
     that.command = null;
+    that.added = IPA.observer();
 
     that.show_edit_page = spec.show_edit_page || show_edit_page;
 
@@ -44,6 +45,7 @@ IPA.entity_adder_dialog = function(spec) {
                 that.hide_message();
                 that.add(
                     function(data, text_status, xhr) {
+                        that.added.notify();
                         var facet = IPA.current_entity.get_facet();
                         facet.refresh();
                         that.close();
@@ -59,6 +61,7 @@ IPA.entity_adder_dialog = function(spec) {
                 that.hide_message();
                 that.add(
                     function(data, text_status, xhr) {
+                        that.added.notify();
                         var label = that.entity.metadata.label_singular;
                         var message = IPA.messages.dialogs.add_confirmation;
                         message = message.replace('${entity}', label);
@@ -79,6 +82,7 @@ IPA.entity_adder_dialog = function(spec) {
                 that.hide_message();
                 that.add(
                     function(data, text_status, xhr) {
+                        that.added.notify();
                         that.close();
                         var result = data.result.result;
                         that.show_edit_page(that.entity, result);
diff --git a/install/ui/automember.js b/install/ui/automember.js
index a9812a71f6a7b60fbd7b9bfe50617b1df38cbfd2..df285973d0e51f5610406e6866eb76ec1f8ae088 100644
--- a/install/ui/automember.js
+++ b/install/ui/automember.js
@@ -33,6 +33,19 @@ IPA.automember.entity = function(spec) {
     IPA.metadata.objects.automember.takes_params.push(pkey_attr);
     IPA.metadata.objects.automember.primary_key = pkey_attr.name;
 
+    spec = spec || {};
+
+    spec.policies = spec.policies || [
+        IPA.facet_update_policy({
+            source_facet: 'usergrouprule',
+            dest_facet: 'searchgroup'
+        }),
+        IPA.facet_update_policy({
+            source_facet: 'hostgrouprule',
+            dest_facet: 'searchhostgroup'
+        })
+    ];
+
     var that = IPA.entity(spec);
 
     that.init = function() {
diff --git a/install/ui/automount.js b/install/ui/automount.js
index 80f5e14383e74b172e36d63dbb1e80769c5db736..db5e403cac5168687e7ca644b6f17a1daed2a598 100644
--- a/install/ui/automount.js
+++ b/install/ui/automount.js
@@ -153,6 +153,16 @@ IPA.automount.map_entity = function(spec) {
 
 IPA.automount.key_entity = function(spec) {
 
+    spec = spec || {};
+
+    spec.policies = spec.policies || [
+        IPA.facet_update_policy({
+            source_facet: 'details',
+            dest_entity: 'automountmap',
+            dest_facet: 'keys'
+        })
+    ];
+
     var that = IPA.entity(spec);
 
     that.init = function() {
diff --git a/install/ui/details.js b/install/ui/details.js
index f7e95ebfe296bda1a27de9195fb277c7693bc8e4..31325813bc5cc96e2f6bcede13c2965f4e5495b2 100644
--- a/install/ui/details.js
+++ b/install/ui/details.js
@@ -535,6 +535,7 @@ IPA.details_facet = function(spec) {
 
     that.update_on_success = function(data, text_status, xhr) {
         that.load(data);
+        that.on_update.notify();
     };
 
     that.update_on_error = function(xhr, text_status, error_thrown) {
diff --git a/install/ui/dns.js b/install/ui/dns.js
index 512d2cc238db45bc239bd3515018a2cef1a1eba6..1aeab5eac9aedde01380f13cd7949fdc8ac13397 100644
--- a/install/ui/dns.js
+++ b/install/ui/dns.js
@@ -251,6 +251,7 @@ IPA.dnszone_details_facet = function(spec) {
 
     that.update_on_success = function(data, text_status, xhr) {
         that.refresh();
+        that.on_update.notify();
     };
 
     that.update_on_error = function(xhr, text_status, error_thrown) {
@@ -903,6 +904,17 @@ IPA.dns.get_record_type = function(type_name) {
 
 IPA.dns.record_entity = function(spec) {
 
+    spec = spec || {};
+
+    spec.policies = spec.policies || [
+        IPA.facet_update_policy({
+            source_facet: 'details',
+            dest_entity: 'dnszone',
+            dest_facet: 'records'
+        }),
+        IPA.adder_facet_update_policy()
+    ];
+
     var that = IPA.entity(spec);
 
     that.init = function() {
@@ -1588,6 +1600,7 @@ IPA.dns.record_type_table_widget = function(spec) {
                 function(data) {
                     that.reload_facet(data);
                     dialog.close();
+                    that.notify_facet_update();
                 },
                 function() {
                     that.refresh_facet();
@@ -1659,6 +1672,7 @@ IPA.dns.record_type_table_widget = function(spec) {
                             that.refresh_facet();
                         }
                         dialog.close();
+                        that.notify_facet_update();
                     },
                     dialog.on_error);
             }
@@ -1682,6 +1696,7 @@ IPA.dns.record_type_table_widget = function(spec) {
                             that.refresh_facet();
                         }
                         dialog.reset();
+                        that.notify_facet_update();
                     },
                     dialog.on_error);
             }
@@ -1773,6 +1788,7 @@ IPA.dns.record_type_table_widget = function(spec) {
             command.on_success = function(data) {
                 that.reload_facet(data);
                 dialog.close();
+                that.notify_facet_update();
             };
             command.on_error = function() {
                 that.refresh_facet();
@@ -1814,6 +1830,11 @@ IPA.dns.record_type_table_widget = function(spec) {
         facet.refresh();
     };
 
+    that.notify_facet_update = function() {
+        var facet = IPA.current_entity.get_facet();
+        facet.on_update.notify();
+    };
+
     that.update = function(values) {
 
         that.idnsname = values.idnsname;
diff --git a/install/ui/entity.js b/install/ui/entity.js
index 6b2be9e6661b2d157a62c5bc8bb6a0fd7847699f..49f30b0b2fb6e7c094409580011a11fb902ef369 100644
--- a/install/ui/entity.js
+++ b/install/ui/entity.js
@@ -31,6 +31,11 @@ IPA.entity = function(spec) {
 
     spec = spec || {};
 
+    spec.policies = spec.policies || [
+        IPA.search_facet_update_policy(),
+        IPA.details_facet_update_policy()
+    ];
+
     var that = {};
 
     that.name = spec.name;
@@ -43,6 +48,11 @@ IPA.entity = function(spec) {
     that.dialog_specs = spec.dialogs || [];
     that.dialogs_created = false;
 
+    that.policies = IPA.entity_policies({
+        entity: that,
+        policies: spec.policies
+    });
+
     that.facets = $.ordered_map();
     that.facet_groups = $.ordered_map();
     that.facet_specs = spec.facets || [];
@@ -116,6 +126,7 @@ IPA.entity = function(spec) {
             var builder = IPA.facet_builder(that);
             builder.build_facets();
             that.facets_created = true;
+            that.policies.facets_created();
         }
 
         if (name === undefined) {
@@ -568,4 +579,144 @@ IPA.dialog_builder = function(entity) {
     };
 
     return that;
+};
+
+IPA.entity_policy = function(spec) {
+
+    spec = spec || {};
+
+    var that = {};
+
+    that.entity = spec.entity;
+
+    that.facets_created = function() {
+    };
+
+    return that;
+};
+
+IPA.entity_policies = function(spec) {
+
+    var that = {};
+
+    that.entity = spec.entity;
+    that.policies = [];
+
+    that.add_policy = function(policy) {
+
+        policy.entity = that.entity;
+        that.policies.push(policy);
+    };
+
+    that.add_policies = function(policies) {
+
+        if (!policies) return;
+
+        for (var i=0; i<policies.length; i++) {
+            that.add_policy(policies[i]);
+        }
+    };
+
+    that.facets_created = function() {
+
+        for (var i=0; i<that.policies.length; i++) {
+            that.policies[i].facets_created();
+        }
+    };
+
+    that.add_policies(spec.policies);
+
+    return that;
+};
+
+IPA.facet_update_policy = function(spec) {
+
+    spec = spec || {};
+
+    var that = IPA.entity_policy();
+
+    that.event = spec.event || 'on_update';
+    that.source_facet_name = spec.source_facet;
+    that.dest_facet_name = spec.dest_facet;
+    that.dest_entity_name = spec.dest_entity;
+
+    that.facets_created = function() {
+
+        that.source_facet = that.entity.get_facet(that.source_facet_name);
+        var dest_entity = that.entity;
+        if (that.dest_entity_name) {
+            dest_entity = IPA.get_entity(that.dest_entity_name);
+            if (!dest_entity) return;
+        }
+        that.dest_facet = dest_entity.get_facet(that.dest_facet_name);
+
+        if (!that.source_facet || !that.dest_facet) return;
+
+        var event = that.source_facet[that.event];
+        if (!event && !event.attach) return;
+
+        event.attach(that.set_expired_flag);
+    };
+
+    that.set_expired_flag = function() {
+
+        that.dest_facet.set_expired_flag();
+    };
+
+    return that;
+};
+
+IPA.adder_facet_update_policy = function(spec) {
+
+    spec = spec || {};
+
+    var that = IPA.entity_policy();
+
+    that.event = spec.event || 'added';
+    that.dialog_name = spec.dialog_name || 'add';
+    that.dest_facet_name = spec.dest_facet || 'details';
+    that.dest_entity_name = spec.dest_entity;
+
+    that.facets_created = function() {
+
+        that.dialog = that.entity.get_dialog(that.dialog_name);
+        var dest_entity = that.entity;
+        if (that.dest_entity_name) {
+            dest_entity = IPA.get_entity(that.dest_entity_name);
+            if (!dest_entity) return;
+        }
+        that.dest_facet = dest_entity.get_facet(that.dest_facet_name);
+
+        if (!that.dialog || !that.dest_facet) return;
+
+        var event = that.dialog[that.event];
+        if (!event && !event.attach) return;
+
+        event.attach(that.set_expired_flag);
+    };
+
+    that.set_expired_flag = function() {
+
+        that.dest_facet.set_expired_flag();
+    };
+
+    return that;
+};
+
+IPA.search_facet_update_policy = function(spec) {
+
+    spec = spec || {};
+    spec.source_facet = 'search';
+    spec.dest_facet = 'details';
+
+    return IPA.facet_update_policy(spec);
+};
+
+IPA.details_facet_update_policy = function(spec) {
+
+    spec = spec || {};
+    spec.source_facet = 'details';
+    spec.dest_facet = 'search';
+
+    return IPA.facet_update_policy(spec);
 };
\ No newline at end of file
diff --git a/install/ui/facet.js b/install/ui/facet.js
index a38bcddfa99bb2ad2dfe96512b9f058193fdbc2a..01e8a935f15fca6834baf2df61575664c013e3da 100644
--- a/install/ui/facet.js
+++ b/install/ui/facet.js
@@ -48,6 +48,7 @@ IPA.facet = function(spec) {
     that.expired_flag = true;
     that.last_updated = null;
     that.expire_timeout = spec.expire_timeout || 600; //[seconds]
+    that.on_update = IPA.observer();
 
     that.dialogs = $.ordered_map();
 
diff --git a/install/ui/hbac.js b/install/ui/hbac.js
index 6bd63d4ecb6a2f1071385a93f0e5edf792604792..007654dca67fdc6749d770cfb4728815fbfce35f 100644
--- a/install/ui/hbac.js
+++ b/install/ui/hbac.js
@@ -518,6 +518,7 @@ IPA.hbacrule_details_facet = function(spec) {
 
     that.update_on_success = function(data, text_status, xhr) {
         that.refresh();
+        that.on_update.notify();
     };
 
     that.update_on_error = function(xhr, text_status, error_thrown) {
diff --git a/install/ui/selinux.js b/install/ui/selinux.js
index 8f800d7debbc9e934423c46a0674e16ab0e9f0ac..ddc8beebcd942e29393595b6b998dfdda89bd8b3 100644
--- a/install/ui/selinux.js
+++ b/install/ui/selinux.js
@@ -282,6 +282,7 @@ IPA.selinux_details_facet = function(spec) {
 
     that.update_on_success = function(data, text_status, xhr) {
         that.refresh();
+        that.on_update.notify();
     };
 
     that.update_on_error = function(xhr, text_status, error_thrown) {
diff --git a/install/ui/sudo.js b/install/ui/sudo.js
index e343d6a4c2d6293f7781d6c19aaf7cc238fbc65f..4fdcc52d1a794e202d16620bba92dc288b2e4f5e 100644
--- a/install/ui/sudo.js
+++ b/install/ui/sudo.js
@@ -633,6 +633,7 @@ IPA.sudorule_details_facet = function(spec) {
 
     that.update_on_success = function(data, text_status, xhr) {
         that.refresh();
+        that.on_update.notify();
     };
 
     that.update_on_error = function(xhr, text_status, error_thrown) {
-- 
1.7.7.6

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

Reply via email to