On 05/26/2015 12:22 PM, Petr Vobornik wrote:
On 05/15/2015 01:50 PM, Petr Vobornik wrote:
On 04/21/2015 04:09 PM, Petr Vobornik wrote:
First iteration of Topology plugin Web UI.

It reflects current state of topology plugin python part which is
implemented in "[PATCH] manage replication topology in the shared tree"
and my wip patch.

I expect that the server API part will change a bit therefore this will
as well.

Graphical visualization/management (ticket 4286)  will be implemented in
separate patch.

https://fedorahosted.org/freeipa/ticket/4997
http://www.freeipa.org/page/V4/Manage_replication_topology



New version attached. It requires stage user web ui patches in order to
apply (I expect that user life cycle backend will be pushed sooner than
topology)

Changes:
- Left host and Right host fields are now host comboboxes
- Connectivity are radio buttons with "both, left-right, right-left,
none" options
- segment name is not a required field in its adder dialog

IMHO "Attributes to strip", "Attributes to replicate", "Attributes for
total update", "Initialize replica", "Session timeout", "Replication
agreement enabled" fields should not be just free-form textboxes, but
they should be more specific, e.g. a checkbox for "Replication agreement
enabled" or integer for "Session timeout", but that should be modified
first in the backend python plugin.



New patchset which replaces the old patch.

Contains Web UI for:
- topologysuffix, topologysegment, domain level, server

Backend is implemented in patches:
- tbabej 325-9
- pvoborni 855, 857



New update which reflects the API change in domain level patches. (domainlevel-show changed to domainlevel-get).

Now it depends only on pvoborni 857-2, the rest was pushed.
--
Petr Vobornik
From b2d17a135c83c04cb1e3fba7efa20a1d545aaa35 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Tue, 21 Apr 2015 15:50:54 +0200
Subject: [PATCH] webui: topology plugin

https://fedorahosted.org/freeipa/ticket/4997
---
 install/ui/doc/categories.json                 |   1 +
 install/ui/src/freeipa/app.js                  |   1 +
 install/ui/src/freeipa/field.js                |   2 +-
 install/ui/src/freeipa/navigation/menu_spec.js |  22 ++
 install/ui/src/freeipa/topology.js             | 393 +++++++++++++++++++++++++
 install/ui/test/data/ipa_init.json             |  11 +
 ipalib/plugins/internal.py                     |  11 +
 7 files changed, 440 insertions(+), 1 deletion(-)
 create mode 100644 install/ui/src/freeipa/topology.js

diff --git a/install/ui/doc/categories.json b/install/ui/doc/categories.json
index 555367a77f966812d3073edfb9e3289248ff63d2..83c24c5efa7f8e52188a30452a9b3119d831592b 100644
--- a/install/ui/doc/categories.json
+++ b/install/ui/doc/categories.json
@@ -252,6 +252,7 @@
                     "otptoken",
                     "radiusproxy",
                     "stageuser",
+                    "topology",
                     "user",
                     "plugins.load",
                     "plugins.login",
diff --git a/install/ui/src/freeipa/app.js b/install/ui/src/freeipa/app.js
index 140fe938f68975310175fb9fadf0ec36db048b72..9b290ab0eee216f8b8adb3181a1b3e7ac22fb351 100644
--- a/install/ui/src/freeipa/app.js
+++ b/install/ui/src/freeipa/app.js
@@ -47,6 +47,7 @@ define([
     './service',
     './sudo',
     './trust',
+    './topology',
     './user',
     './stageuser',
     'dojo/domReady!'
diff --git a/install/ui/src/freeipa/field.js b/install/ui/src/freeipa/field.js
index f26033ce25a15cface945eeecc69ca503179d30c..fdf925e3d7adc62622e0c9e5e1440eefbdac807b 100644
--- a/install/ui/src/freeipa/field.js
+++ b/install/ui/src/freeipa/field.js
@@ -821,7 +821,7 @@ field.Adapter = declare(null, {
         var dr = data.result;
         var record = null;
         if (dr) {
-            if (dr.result) record = dr.result;
+            if (IPA.defined(dr.result)) record = dr.result;
             else if (dr.results) {
                 var result = dr.results[this.result_index];
                 if (result) record = result.result;
diff --git a/install/ui/src/freeipa/navigation/menu_spec.js b/install/ui/src/freeipa/navigation/menu_spec.js
index 13f533d1a6fbb21c73e1f0e5fe1df2836c99f832..c35445f12e36c5dc49033723d8efdcaed7331002 100644
--- a/install/ui/src/freeipa/navigation/menu_spec.js
+++ b/install/ui/src/freeipa/navigation/menu_spec.js
@@ -184,6 +184,28 @@ var nav = {};
                         { entity: 'trustconfig' }
                     ]
                 },
+                {
+                    entity: 'topologysuffix',
+                    label: '@i18n:tabs.topology',
+                    facet: 'search',
+                    children: [
+                        {
+                            entity: 'topologysuffix',
+                            facet: 'search',
+                            hidden: true
+                        },
+                        {
+                            entity: 'server',
+                            facet: 'search',
+                            hidden: true
+                        },
+                        {
+                            entity: 'domainlevel',
+                            facet: 'details',
+                            hidden: true
+                        }
+                    ]
+                },
                 { entity: 'config' }
             ]
         }
diff --git a/install/ui/src/freeipa/topology.js b/install/ui/src/freeipa/topology.js
new file mode 100644
index 0000000000000000000000000000000000000000..51714d99f9e1b3f6a8099f64333eb74f48016a95
--- /dev/null
+++ b/install/ui/src/freeipa/topology.js
@@ -0,0 +1,393 @@
+//
+// Copyright (C) 2015  FreeIPA Contributors see COPYING for license
+//
+
+define([
+        'dojo/_base/lang',
+        'dojo/_base/declare',
+        'dojo/on',
+        './builder',
+        './ipa',
+        './jquery',
+        './menu',
+        './metadata',
+        './phases',
+        './reg',
+        './rpc',
+        './text',
+        './details',
+        './facet',
+        './field',
+        './search',
+        './entity'],
+            function(lang, declare, on, builder, IPA, $, menu, metadata_provider,
+                phases, reg, rpc, text, mod_details, mod_facet, mod_field) {
+/**
+ * Topology module
+ * @class
+ * @singleton
+ */
+var topology = IPA.topology = {
+
+    search_facet_group: {
+        name: 'search',
+        label: '@i18n:tabs.topology',
+        facets: {
+            suffix_search: 'topologysuffix_search',
+            server_search: 'server_search',
+            domainlevel: 'domainlevel_details'
+        }
+    }
+};
+
+var make_suffix_spec = function() {
+return {
+    name: 'topologysuffix',
+    enable_test: function() {
+        return true;
+    },
+    facet_groups: [ 'segments', 'settings' ],
+    facets: [
+        {
+            $type: 'search',
+            disable_facet_tabs: false,
+            tabs_in_sidebar: true,
+            tab_label: '@mo:topologysuffix.label',
+            facet_groups: [topology.search_facet_group],
+            facet_group: 'search',
+            columns: [
+                'cn',
+                'iparepltopoconfroot'
+            ]
+        },
+        {
+            $type: 'nested_search',
+            facet_group: 'segments',
+            nested_entity: 'topologysegment',
+            search_all_entries: true,
+            label: '@mo:topologysegment.label',
+            tab_label: '@mo:topologysegment.label',
+            name: 'topologysegment',
+            columns: [
+                'cn',
+                'iparepltoposegmentleftnode',
+                'iparepltoposegmentrightnode',
+                'iparepltoposegmentdirection'
+            ]
+        },
+        {
+            $type: 'details',
+            sections: [
+                {
+                    name: 'details',
+                    fields: [
+                        'cn',
+                        'iparepltopoconfroot'
+                    ]
+                }
+            ]
+        }
+    ],
+    adder_dialog: {
+        fields: [
+            'cn',
+            'iparepltopoconfroot'
+        ]
+    }
+};};
+
+
+var make_segment_spec = function() {
+return {
+    name: 'topologysegment',
+    containing_entity: 'topologysuffix',
+    enable_test: function() {
+        return true;
+    },
+    facets: [
+        {
+            $type: 'details',
+            disable_breadcrumb: false,
+            sections: [
+                {
+                    name: 'details',
+                    label: '@i18n:objects.topology.segment_details',
+                    fields: [
+                        'cn',
+                        {
+                            $type: 'entity_select',
+                            name: 'iparepltoposegmentleftnode',
+                            other_entity: 'server',
+                            other_field: 'cn',
+                            z_index: 2
+                        },
+                        {
+                            $type: 'entity_select',
+                            name: 'iparepltoposegmentrightnode',
+                            other_entity: 'server',
+                            other_field: 'cn',
+                            z_index: 1
+                        },
+                        {
+                            $type: 'radio',
+                            name: 'iparepltoposegmentdirection',
+                            options: IPA.create_options([
+                                'both', 'left-right', 'right-left', 'none'
+                            ]),
+                            default_value: 'both'
+                        }
+                    ]
+                },
+                {
+                    name: 'replication_config',
+                    label: '@i18n:objects.topology.replication_config',
+                    fields: [
+                        {
+                            $type: 'radio',
+                            name: 'nsds5replicaenabled',
+                            options: ['on', 'off'],
+                            default_value: 'on'
+                        },
+                        'nsds5replicatimeout',
+                        'nsds5replicastripattrs',
+                        'nsds5replicatedattributelist',
+                        'nsds5replicatedattributelisttotal'
+                    ]
+                }
+            ]
+        }
+    ],
+    adder_dialog: {
+        fields: [
+            {
+                name: 'cn',
+                required: false
+            },
+            {
+                $type: 'entity_select',
+                name: 'iparepltoposegmentleftnode',
+                other_entity: 'server',
+                other_field: 'cn',
+                z_index: 2
+            },
+            {
+                $type: 'entity_select',
+                name: 'iparepltoposegmentrightnode',
+                other_entity: 'server',
+                other_field: 'cn',
+                z_index: 1
+            },
+            {
+                $type: 'radio',
+                name: 'iparepltoposegmentdirection',
+                options: IPA.create_options([
+                    'both', 'left-right', 'right-left', 'none'
+                ]),
+                default_value: 'both'
+            }
+        ]
+    }
+};};
+
+var make_server_spec = function() {
+return {
+    name: 'server',
+    facets: [
+           {
+            $type: 'search',
+            no_update: true,
+            disable_facet_tabs: false,
+            tabs_in_sidebar: true,
+            tab_label: '@mo:server.label',
+            facet_groups: [topology.search_facet_group],
+            facet_group: 'search',
+            columns: [
+                'cn',
+                'ipamindomainlevel',
+                'ipamaxdomainlevel',
+                'iparepltopomanagedsuffix'
+            ]
+        },
+        {
+            $type: 'details',
+            no_update: true,
+            disable_facet_tabs: true,
+            sections: [
+                {
+                    name: 'details',
+                    fields: [
+                        { name: 'cn', read_only: true },
+                        { name: 'ipamindomainlevel', read_only: true },
+                        { name: 'ipamaxdomainlevel', read_only: true },
+                        { name: 'iparepltopomanagedsuffix', read_only: true }
+                    ]
+                }
+            ]
+        }
+    ]
+};};
+
+var make_domainlevel_spec = function() {
+return {
+    name: 'domainlevel',
+    facets: [
+        {
+            $type: 'details',
+            get_all_attrs: false,
+            check_rights: false,
+            no_update: true,
+            refresh_command_name: 'get',
+            disable_facet_tabs: false,
+            tabs_in_sidebar: true,
+            tab_label: '@mo:domainlevel.label',
+            facet_groups: [topology.search_facet_group],
+            facet_group: 'search',
+            sections: [
+                {
+                    name: 'details',
+                    fields: [
+                        {
+                            name: 'ipadomainlevel',
+                            read_only: true,
+                            adapter: topology.domainlevel_adapter
+                        }
+                    ]
+                }
+            ],
+            actions: ['domainlevel_set'],
+            control_buttons: [{
+                label: '@i18n:objects.domainlevel.set',
+                name: 'domainlevel_set'
+            }]
+        }
+    ]
+};};
+
+topology.domainlevel_adapter = declare([mod_field.Adapter], {
+    load: function(data) {
+        return [this.get_record(data)];
+    }
+});
+
+
+topology.domainlevel_metadata = function(spec, context) {
+    var metadata = metadata_provider.source;
+    metadata.objects.domainlevel = {
+        name: 'domainlevel',
+        label: text.get('@i18n:objects.domainlevel.label'),
+        label_singular: text.get('@i18n:objects.domainlevel.label_singular'),
+        takes_params: [
+            {
+                'class': "Int",
+                doc: "",
+                flags: [],
+                label: text.get("@i18n:objects.domainlevel.ipadomainlevel"),
+                maxvalue: 2147483647,
+                minvalue: 0,
+                name: "ipadomainlevel",
+                type: "int"
+            }
+        ]
+    };
+    return spec;
+};
+
+/**
+ * Set Domain Level Action
+ *
+ * @class topology.domainlevel_set_action
+ * @extends {IPA.action}
+ */
+topology.domainlevel_set_action = function(spec) {
+
+    spec = spec || {};
+    spec.name = spec.name || 'domainlevel_set';
+    spec.label = spec.label || '@i18n:objects.domainlevel.set';
+    var that = IPA.action(spec);
+
+    /**
+     * Dialog spec
+     * @property {Object}
+     */
+    that.dialog = spec.dialog || {
+        $type: 'command',
+        entity: 'domainlevel',
+        method: 'set',
+        title: '@i18n:objects.domainlevel.set',
+        confirm_button_label: '@i18n:buttons.set',
+        fields: [
+            {
+                name: 'ipadomainlevel',
+                primary_key: true
+            }
+        ]
+    };
+
+    /**
+     * Refresh facet after successful action
+     * @property {boolean} refresh=true
+     */
+    that.refresh = spec.refresh !== undefined ? spec.refresh : true;
+
+    /**
+     * @inheritDoc
+     */
+    that.execute_action = function(facet) {
+
+        var dialog = builder.build('dialog', that.dialog);
+        dialog.succeeded.attach(function() {
+            if (that.refresh) facet.refresh();
+        });
+        dialog.open();
+    };
+    return that;
+};
+
+
+
+/**
+ * Topology suffix entity specification object
+ * @member topology
+ */
+topology.suffix_spec = make_suffix_spec();
+
+/**
+ * Topology segment entity specification object
+ * @member topology
+ */
+topology.segment_spec = make_segment_spec();
+
+/**
+ * IPA server entity specification object
+ * @member topology
+ */
+topology.server_spec = make_server_spec();
+
+/**
+ * Domain Level entity specification object
+ * @member topology
+ */
+topology.domainlevel_spec = make_domainlevel_spec();
+
+
+/**
+ * Register entity
+ * @member topology
+ */
+topology.register = function() {
+    var e = reg.entity;
+    var a = reg.action;
+
+    e.register({type: 'topologysuffix', spec: topology.suffix_spec});
+    e.register({type: 'topologysegment', spec: topology.segment_spec});
+    e.register({type: 'server', spec: topology.server_spec});
+    e.register({type: 'domainlevel', spec: topology.domainlevel_spec});
+
+    a.register('domainlevel_set', topology.domainlevel_set_action);
+};
+
+phases.on('registration', topology.register);
+phases.on('post-metadata', topology.domainlevel_metadata);
+
+return topology;
+});
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index cbaf69e587e93e431f4911afc37d069736b133c3..e5d306cd0cc9d39e05ebce0c45538a859eb89992 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -307,6 +307,12 @@
                             "soamname_change_message": "Do you want to check if new authoritative nameserver address is in DNS",
                             "soamname_change_title": "Authoritative nameserver change"
                         },
+                        "domainlevel": {
+                            "label": "Domain Level",
+                            "label_singular": "Domain Level",
+                            "ipadomainlevel": "Level",
+                            "set": "Set Domain Level"
+                        },
                         "group": {
                             "details": "Group Settings",
                             "external": "External",
@@ -545,6 +551,10 @@
                             "specified_users": "Specified Users and Groups",
                             "user": "Who"
                         },
+                        "topology": {
+                            "segment_details": "Segment details",
+                            "replication_config": "Replication configuration",
+                        },
                         "trust": {
                             "account": "Account",
                             "admin_account": "Administrative account",
@@ -641,6 +651,7 @@
                         "policy": "Policy",
                         "role": "Role Based Access Control",
                         "sudo": "Sudo",
+                        "topology": "Topology",
                         "trust": "Trusts"
                     },
                     "true": "True",
diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py
index bb05a74e5c3fd36bad78a7fdba108b3263c223f1..ff096616d5e9bdc6737ee2d8b087fbded18ca2af 100644
--- a/ipalib/plugins/internal.py
+++ b/ipalib/plugins/internal.py
@@ -452,6 +452,12 @@ class i18n_messages(Command):
                 "soamname_change_message": _("Do you want to check if new authoritative nameserver address is in DNS"),
                 "soamname_change_title": _("Authoritative nameserver change"),
             },
+            "domainlevel": {
+                "label": _("Domain Level"),
+                "label_singular": _("Domain Level"),
+                "ipadomainlevel": _("Level"),
+                "set": _("Set Domain Level"),
+            },
             "group": {
                 "details": _("Group Settings"),
                 "external": _("External"),
@@ -691,6 +697,10 @@ class i18n_messages(Command):
                 "specified_users": _("Specified Users and Groups"),
                 "user": _("Who"),
             },
+            "topology": {
+                "segment_details": _("Segment details"),
+                "replication_config": _("Replication configuration"),
+            },
             "trust": {
                 "account": _("Account"),
                 "admin_account": _("Administrative account"),
@@ -787,6 +797,7 @@ class i18n_messages(Command):
             "policy": _("Policy"),
             "role": _("Role Based Access Control"),
             "sudo": _("Sudo"),
+            "topology": _("Topology"),
             "trust": _("Trusts"),
         },
         "true": _("True"),
-- 
2.1.0

From 2b4c317e39abe9922fce8b701d82b052688fa70c Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Mon, 25 May 2015 19:15:16 +0200
Subject: [PATCH] webui: make usage of --all in details facet optional

refactoring for domains level UI
https://fedorahosted.org/freeipa/ticket/4997
---
 install/ui/src/freeipa/details.js | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/install/ui/src/freeipa/details.js b/install/ui/src/freeipa/details.js
index 01fcfc56508449ea1f5d6ec685a38119f94621a3..98c2bdc76c5c223532f9f08a71f56c350d213cf9 100644
--- a/install/ui/src/freeipa/details.js
+++ b/install/ui/src/freeipa/details.js
@@ -552,6 +552,15 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
     that.check_rights = spec.check_rights !== undefined ? spec.check_rights : true;
 
     /**
+     * Get all fields
+     *
+     * Controls obtaining of all attributes on refresh and update
+     *
+     * @property {boolean}
+     */
+    that.get_all_attrs = spec.get_all_attrs !== undefined ? spec.get_all_attrs: true;
+
+    /**
      * Facet label
      * @property {string}
      */
@@ -868,7 +877,8 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
 
         var args = that.get_pkeys();
 
-        var options = { all: true };
+        var options = {};
+        if (that.get_all_attrs) options.all = true;
         if (that.check_rights) options.rights = true;
 
         var command = rpc.command({
@@ -992,7 +1002,8 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
      */
     that.create_refresh_command = function() {
 
-        var options = { all: true };
+        var options = {};
+        if (that.get_all_attrs) options.all = true;
         if (that.check_rights) options.rights = true;
 
         var command = rpc.command({
-- 
2.1.0

From c6fe1204f16466058a97366a1b383ecf67463eb6 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 22 May 2015 14:17:08 +0200
Subject: [PATCH] webui: use command_dialog as a base class for password dialog

refactoring for:
https://fedorahosted.org/freeipa/ticket/4997
---
 install/ui/doc/categories.json             |   1 -
 install/ui/src/freeipa/dialogs/password.js | 202 +----------------------------
 2 files changed, 6 insertions(+), 197 deletions(-)

diff --git a/install/ui/doc/categories.json b/install/ui/doc/categories.json
index 8741d82e11f11c7fb75fdf187937c83af08697b3..555367a77f966812d3073edfb9e3289248ff63d2 100644
--- a/install/ui/doc/categories.json
+++ b/install/ui/doc/categories.json
@@ -49,7 +49,6 @@
                     "IPA.opened_dialogs",
                     "IPA.dialog_button",
                     "IPA.confirm_mixin",
-                    "dialogs.password.dialog",
                     "*_dialog"
                 ]
             },
diff --git a/install/ui/src/freeipa/dialogs/password.js b/install/ui/src/freeipa/dialogs/password.js
index fa672901d589aaf7308ff7e2b6af545be544df4b..f25f7ac60477b1c85b5a6ede23cd93724a89e642 100644
--- a/install/ui/src/freeipa/dialogs/password.js
+++ b/install/ui/src/freeipa/dialogs/password.js
@@ -27,9 +27,8 @@ define([
         '../rpc',
         '../text',
         '../dialog'],
-            function(lang, builder, IPA, phases, reg, rpc, text) {
+            function(lang, builder, IPA, phases, reg, rpc, text, dialogs) {
 
-var dialogs = {}; // dummy object
 /**
  * Password dialog module
  * @class
@@ -49,6 +48,9 @@ dialogs.password.default_fields_pre_op =  function(spec) {
 
     spec.title = spec.title || '@i18n:password.reset_password';
     spec.width = spec.width || 400;
+    spec.method = spec.method || 'mod';
+    spec.success_message = spec.success_message || '@i18n:password.password_change_complete';
+    spec.confirm_button_label = spec.confirm_button_label || '@i18n:password.reset_password';
     spec.sections = spec.sections || [
         {
             name: 'general',
@@ -77,198 +79,6 @@ dialogs.password.default_fields_pre_op =  function(spec) {
 };
 
 /**
- * Dialog's post_ops
- */
-dialogs.password.default_post_op = function(dialog, spec) {
-    dialog.init();
-    return dialog;
-};
-
-/**
- * Password dialog
- * @class
- * @extends IPA.dialog
- * @mixins IPA.confirm_mixin
- */
-dialogs.password.dialog = function(spec) {
-
-    var that = IPA.dialog(spec);
-
-    IPA.confirm_mixin().apply(that);
-
-    /**
-     * Method for setting password
-     * @property {string}
-     */
-    that.method = spec.method || 'mod';
-
-    /**
-     * Command args
-     * @property {string[]}
-     */
-    that.args = spec.args || [];
-
-    /**
-     * Command additional options
-     * @property {Object}
-     */
-    that.options = spec.options || {};
-
-    /**
-     * Success message
-     * @property {string}
-     */
-    that.success_message = spec.success_message || '@i18n:password.password_change_complete';
-
-    /**
-     * Set button label
-     * @property {string}
-     */
-    that.confirm_button_label = spec.confirm_button_label || '@i18n:password.reset_password';
-
-    /**
-     * Failed event
-     * @event
-     */
-    that.failed = IPA.observer();
-
-    /**
-     * Succeeded event
-     * @event
-     */
-    that.succeeded = IPA.observer();
-
-    /**
-     * Execute password change
-     */
-    that.execute = function() {
-
-        var command = that.create_command();
-        command.execute();
-    };
-
-    /**
-     * Confirm handler
-     * @protected
-     */
-    that.on_confirm = function() {
-
-        if (!that.validate()) return;
-        that.execute();
-        that.close();
-    };
-
-    /**
-     * Create buttons
-     * @protected
-     */
-    that.create_buttons = function() {
-
-        that.create_button({
-            name: 'confirm',
-            label: that.confirm_button_label,
-            click: function() {
-                that.on_confirm();
-            }
-        });
-
-        that.create_button({
-            name: 'cancel',
-            label: '@i18n:buttons.cancel',
-            click: function() {
-                that.close();
-            }
-        });
-    };
-
-    /**
-     * Make options for command
-     * @protected
-     */
-    that.make_otions = function() {
-
-        var options = {};
-        lang.mixin(options, that.options);
-
-        var fields = that.fields.get_fields();
-        for (var j=0; j<fields.length; j++) {
-            var field = fields[j];
-            var values = field.save();
-            if (!values || values.length === 0 || !field.enabled) continue;
-            if (field.flags.indexOf('no_command') > -1) continue;
-
-            if (values.length === 1) {
-                options[field.param] = values[0];
-            } else {
-                options[field.param] = values;
-            }
-        }
-        return options;
-    };
-
-    /**
-     * Create command
-     * @protected
-     */
-    that.create_command = function() {
-
-        var options = that.make_otions();
-        var entity = null;
-        if (that.entity) entity = that.entity.name;
-        var command = rpc.command({
-            entity: entity,
-            method: that.method,
-            args: that.args,
-            options: options,
-            on_success: function(data) {
-                that.on_success();
-            },
-            on_error: function() {
-                that.on_error();
-            }
-        });
-        return command;
-    };
-
-    /**
-     * Get success message
-     * @protected
-     */
-    that.get_success_message = function() {
-        return text.get(that.success_message);
-    };
-
-    /**
-     * Success handler
-     * @protected
-     * @param {Object} data
-     */
-    that.on_success = function(data) {
-        that.succeeded.notify([data], that);
-        IPA.notify_success(that.get_success_message());
-    };
-
-    /**
-     * Error handler
-     * @protected
-     */
-    that.on_error = function(xhr, status, error) {
-        that.failed.notify([xhr, status, error], that);
-    };
-
-    /**
-     * Init function
-     *
-     * - should be called right after instance creation
-     */
-    that.init = function() {
-        that.create_buttons();
-    };
-
-    return that;
-};
-
-/**
  * Action to open a password dialog
  * @class
  * @extends facet.action
@@ -324,9 +134,9 @@ dialogs.password.register = function() {
 
     d.register({
         type: 'password',
-        factory: DP.dialog,
+        factory: dialogs.command_dialog,
         pre_ops: [DP.default_fields_pre_op],
-        post_ops: [DP.default_post_op]
+        post_ops: [dialogs.command_dialog_post_op]
     });
 
     a.register('password', DP.action);
-- 
2.1.0

From c6dc5474531d15bfec86098e329aea0cc37dadbf Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 22 May 2015 13:39:18 +0200
Subject: [PATCH] webui: IPA.command_dialog - a new dialog base class

refactoring for:

https://fedorahosted.org/freeipa/ticket/4997
---
 install/ui/src/freeipa/dialog.js   | 218 ++++++++++++++++++++++++++++++++++++-
 install/ui/test/data/ipa_init.json |   1 +
 ipalib/plugins/internal.py         |   1 +
 3 files changed, 217 insertions(+), 3 deletions(-)

diff --git a/install/ui/src/freeipa/dialog.js b/install/ui/src/freeipa/dialog.js
index 6cac66794c73beac971d42407d10e9fb0fce31f9..f8f1bba78bee44e6d5e78be9c6c906bd55b9c698 100644
--- a/install/ui/src/freeipa/dialog.js
+++ b/install/ui/src/freeipa/dialog.js
@@ -30,12 +30,14 @@ define([
        './jquery',
        './phases',
        './reg',
+       './rpc',
        './text',
        './field',
        './widget'],
-       function(lang, keys, topic, Evented, builder, IPA, $, phases, reg, text,
-        field_mod, widget_mod) {
+       function(lang, keys, topic, Evented, builder, IPA, $, phases, reg, rpc,
+        text, field_mod, widget_mod) {
 
+var dialogs = {};
 
 /**
  * Opened dialogs
@@ -1571,6 +1573,200 @@ IPA.confirm_mixin = function() {
     };
 };
 
+
+/**
+ * Dialog's post_ops
+ */
+dialogs.command_dialog_post_op = function(dialog, spec) {
+    dialog.init();
+    return dialog;
+};
+
+
+/**
+ * General command dialog
+ * @class
+ * @extends IPA.dialog
+ * @mixins IPA.confirm_mixin
+ */
+IPA.command_dialog = dialogs.command_dialog = function(spec) {
+
+    var that = IPA.dialog(spec);
+
+    IPA.confirm_mixin().apply(that);
+
+    /**
+     * Method for setting password
+     * @property {string}
+     */
+    that.method = spec.method || 'mod';
+
+    /**
+     * Command args
+     * @property {string[]}
+     */
+    that.args = spec.args || [];
+
+    /**
+     * Command additional options
+     * @property {Object}
+     */
+    that.options = spec.options || {};
+
+    /**
+     * Success message
+     * @property {string}
+     */
+    that.success_message = spec.success_message || '@i18n:dialogs.success';
+
+    /**
+     * Set button label
+     * @property {string}
+     */
+    that.confirm_button_label = spec.confirm_button_label || '@i18n:buttons.ok';
+
+    /**
+     * Failed event
+     * @event
+     */
+    that.failed = IPA.observer();
+
+    /**
+     * Succeeded event
+     * @event
+     */
+    that.succeeded = IPA.observer();
+
+    /**
+     * Execute change
+     */
+    that.execute = function() {
+
+        var command = that.create_command();
+        command.execute();
+    };
+
+    /**
+     * Confirm handler
+     * @protected
+     */
+    that.on_confirm = function() {
+
+        if (!that.validate()) return;
+        that.execute();
+        that.close();
+    };
+
+    /**
+     * Create buttons
+     * @protected
+     */
+    that.create_buttons = function() {
+
+        that.create_button({
+            name: 'confirm',
+            label: that.confirm_button_label,
+            click: function() {
+                that.on_confirm();
+            }
+        });
+
+        that.create_button({
+            name: 'cancel',
+            label: '@i18n:buttons.cancel',
+            click: function() {
+                that.close();
+            }
+        });
+    };
+
+    /**
+     * Make options for command
+     * @protected
+     */
+    that.make_otions = function() {
+
+        var options = {};
+        lang.mixin(options, that.options);
+
+        var fields = that.fields.get_fields();
+        for (var j=0; j<fields.length; j++) {
+            var field = fields[j];
+            var values = field.save();
+            if (!values || values.length === 0 || !field.enabled) continue;
+            if (field.flags.indexOf('no_command') > -1) continue;
+
+            if (values.length === 1) {
+                options[field.param] = values[0];
+            } else {
+                options[field.param] = values;
+            }
+        }
+        return options;
+    };
+
+    /**
+     * Create command
+     * @protected
+     */
+    that.create_command = function() {
+
+        var options = that.make_otions();
+        var entity = null;
+        if (that.entity) entity = that.entity.name;
+        var command = rpc.command({
+            entity: entity,
+            method: that.method,
+            args: that.args,
+            options: options,
+            on_success: function(data) {
+                that.on_success();
+            },
+            on_error: function() {
+                that.on_error();
+            }
+        });
+        return command;
+    };
+
+    /**
+     * Get success message
+     * @protected
+     */
+    that.get_success_message = function() {
+        return text.get(that.success_message);
+    };
+
+    /**
+     * Success handler
+     * @protected
+     * @param {Object} data
+     */
+    that.on_success = function(data) {
+        that.succeeded.notify([data], that);
+        IPA.notify_success(that.get_success_message());
+    };
+
+    /**
+     * Error handler
+     * @protected
+     */
+    that.on_error = function(xhr, status, error) {
+        that.failed.notify([xhr, status, error], that);
+    };
+
+    /**
+     * Init function
+     *
+     * - should be called right after instance creation
+     */
+    that.init = function() {
+        that.create_buttons();
+    };
+
+    return that;
+};
+
 /**
  * Dialog builder
  * - added as builder for 'dialog' registry
@@ -1580,5 +1776,21 @@ var dialog_builder = builder.get('dialog');
 dialog_builder.factory = IPA.dialog;
 reg.set('dialog', dialog_builder.registry);
 
-return {};
+/**
+ * Register dialog
+ */
+dialogs.register = function() {
+
+    var d = reg.dialog;
+
+    d.register({
+        type: 'command',
+        factory: dialogs.command_dialog,
+        post_ops: [dialogs.command_dialog_post_op]
+    });
+};
+
+phases.on('registration', dialogs.register);
+
+return dialogs;
 });
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index a0ad94760e9ec706639166bf40347d8a2606a13a..cbaf69e587e93e431f4911afc37d069736b133c3 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -116,6 +116,7 @@
                         "remove_empty": "Select entries to be removed.",
                         "remove_title": "Remove ${entity}",
                         "show_details": "Show details",
+                        "success": "Success",
                         "validation_message": "Input form contains invalid or missing values.",
                         "validation_title": "Validation error"
                     },
diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py
index 53a70d4502f7df9f631ed5657f88554463109fe7..bb05a74e5c3fd36bad78a7fdba108b3263c223f1 100644
--- a/ipalib/plugins/internal.py
+++ b/ipalib/plugins/internal.py
@@ -259,6 +259,7 @@ class i18n_messages(Command):
             "remove_empty": _("Select entries to be removed."),
             "remove_title": _("Remove ${entity}"),
             "show_details": _("Show details"),
+            "success": _("Success"),
             "validation_title": _("Validation error"),
             "validation_message": _("Input form contains invalid or missing values."),
         },
-- 
2.1.0

From dfb84c95f4c4e0d9d658bb842bf0d582b56d675b Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Tue, 26 May 2015 15:26:15 +0200
Subject: [PATCH] webui: configurable refresh command

Allows to change the default 'show' command to something different. E.g. 'get'
---
 install/ui/src/freeipa/details.js | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/install/ui/src/freeipa/details.js b/install/ui/src/freeipa/details.js
index 98c2bdc76c5c223532f9f08a71f56c350d213cf9..c708a878b7d6d29815535b7508da0c4cc30a3b5c 100644
--- a/install/ui/src/freeipa/details.js
+++ b/install/ui/src/freeipa/details.js
@@ -522,6 +522,15 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
      */
     that.entity = IPA.get_entity(spec.entity);
 
+
+    /**
+     * Name of refresh RPC command
+     *
+     * - defaults to 'show'
+     * @property {string}
+     */
+    that.refresh_command_name = spec.refresh_command_name || 'show';
+
     /**
      * Name of update command
      *
@@ -992,7 +1001,7 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
      * @return {string}
      */
     that.get_refresh_command_name = function() {
-        return that.entity.name+'_show';
+        return that.entity.name+'_'+that.refresh_command_name;
     };
 
     /**
@@ -1009,7 +1018,7 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
         var command = rpc.command({
             name: that.get_refresh_command_name(),
             entity: that.entity.name,
-            method: 'show',
+            method: that.refresh_command_name,
             options: options
         });
 
-- 
2.1.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to