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
--
Petr Vobornik
From a55c3e79f4174283c682e2c976e367ced4b8aff2 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/navigation/menu_spec.js |  22 ++
 install/ui/src/freeipa/topology.js             | 392 +++++++++++++++++++++++++
 install/ui/test/data/ipa_init.json             |  11 +
 ipalib/plugins/internal.py                     |  11 +
 6 files changed, 438 insertions(+)
 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/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..4f41591463740443dcf7dfeb1c70ffb686f9bad0
--- /dev/null
+++ b/install/ui/src/freeipa/topology.js
@@ -0,0 +1,392 @@
+//
+// 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,
+            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 935b6adf947080370d7a31c8cb68f2a8d1291762 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..0598e0218edf348a17152d080987ad5cd5dc4355 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
+     *
+     * @type {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 e33aa83dab5e28c99572f9d9fc42ff40a80e4cfc 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 d992b7edc9b4b6b1a6776e38ac3d238ac0066f1b 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

-- 
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