From cf76c87cc7c0f090ec4ec4a55ac7c9b05804d902 Mon Sep 17 00:00:00 2001 From: Marek Lycka Date: Thu, 24 Aug 2017 14:50:38 +0200 Subject: [PATCH] Replaces multi select combos with transfer tables Implements an angular-python bridge that allows django/horizon forms to use transfer tables (as seen in other parts of horizon, e.g.: computes launch instance dialog) as form fields. These fields are then used to replace the multi select combos boxes in the different GBPUI dialogs/forms. Note 1: The add and remove policy rule set actions in group details "Provided Policy Rule Set" and "Consumed Policy Rule Set" are currently unaffected. These two tabs do not follow the "standard" horizon method of adding and removing items through one transfer table; instead, it uses two different dialogs to carry out each operation separately. This should be addressed in a separate patchset. Note 2: This is a bit of a stop gap measure, as horizon is slowly moving away from native django based dialogs and wizards to AngularJS. The goal should ultimately be to do the same in GBPUI. Change-Id: I01c9dc08b1bc35309d62eb3da0bd26f3795867ab Partial-Bug: 1712814 --- gbpui/_1550_gbp_project_add_panel_group.py | 3 + gbpui/fields.py | 80 ++++++++++++ gbpui/panels/application_policy/forms.py | 12 +- gbpui/panels/application_policy/workflows.py | 21 ++-- gbpui/panels/network_policy/forms.py | 25 ++-- gbpui/panels/policytargets/forms.py | 15 ++- gbpui/panels/policytargets/workflows.py | 21 ++-- gbpui/static/dashboard/gbpui/gbpui.module.js | 25 ++++ .../d-select.directive.js | 90 ++++++++++++++ .../d-table.directive.js | 91 ++++++++++++++ .../transfer-table-bridge.html | 114 ++++++++++++++++++ .../transfer-table.module.js | 17 +++ 12 files changed, 475 insertions(+), 39 deletions(-) create mode 100644 gbpui/static/dashboard/gbpui/gbpui.module.js create mode 100644 gbpui/static/dashboard/gbpui/transfer-table-bridge/d-select.directive.js create mode 100644 gbpui/static/dashboard/gbpui/transfer-table-bridge/d-table.directive.js create mode 100644 gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table-bridge.html create mode 100644 gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table.module.js diff --git a/gbpui/_1550_gbp_project_add_panel_group.py b/gbpui/_1550_gbp_project_add_panel_group.py index d57de7b..25d20e1 100644 --- a/gbpui/_1550_gbp_project_add_panel_group.py +++ b/gbpui/_1550_gbp_project_add_panel_group.py @@ -14,3 +14,6 @@ ADD_INSTALLED_APPS = ['gbpui', ] PANEL_GROUP = 'GroupPolicyPanels' PANEL_GROUP_NAME = 'Policy' PANEL_GROUP_DASHBOARD = 'project' + +AUTO_DISCOVER_STATIC_FILES = True +ADD_ANGULAR_MODULES = ['gbpui', ] diff --git a/gbpui/fields.py b/gbpui/fields.py index 8046a7e..4ec3f2b 100644 --- a/gbpui/fields.py +++ b/gbpui/fields.py @@ -16,6 +16,11 @@ from django.forms import TextInput from django.forms import widgets from django.utils.safestring import mark_safe +from django.forms.utils import flatatt +from django.utils.html import format_html + +from django.utils.translation import ugettext_lazy as _ + class DynamicMultiSelectWidget(widgets.SelectMultiple): @@ -84,3 +89,78 @@ class DropdownEditWidget(TextInput): data_list += '"); + option.attr("value", optionObject.id); + option.append(optionObject.name); + $elem.append(option); + }); + + // This change listener watches for changes to the raw + // HTML select element; since the select should be hidden, + // the only possible change is the creation of a new + // option using the horizon add button. + $elem.change(function () { + // Find the last option in the select, since the + // addition is done by Horizon appending the a new + // option element + var option = $(this).find("option").last(); + + // Create a valid option object and make it available + // at the end of the available list + var val = { + 'id': option.attr('value'), + 'name': option.text() + }; + $scope.tableData.available.push(val); + + // Deallocate all the objects using the built in + // transfer table controller deallocation method + var toDeallocate = $scope.tableData.allocated.slice(); + $.each(toDeallocate, function (index, object) { + $scope.trCtrl.deallocate(object); + }); + // Notify the scope of the deallocations + $scope.$apply(); + + // Allocate the new option; this mimicks te behaviour + // of the normal Horizon based adding + $scope.trCtrl.allocate(val); + + // Notify the scope of the allocation changes + $scope.$apply(); + }); + + // The directive watches for a changes in the allocated + // list to dynamically set values for the hidden element. + $scope.$watchCollection( + function (scope) { + return $scope.tableData.allocated; + }, + function (newValue, oldValue) { + var values = $.map( + newValue, function (value, index) { + return value.id; + }); + $elem.val(values); + } + ); + + // Sets initial values as allocated when appropriate + $.each($scope.initial, function (index, initialObject) { + $scope.trCtrl.allocate(initialObject); + }); + + + } + } + }); +})(); diff --git a/gbpui/static/dashboard/gbpui/transfer-table-bridge/d-table.directive.js b/gbpui/static/dashboard/gbpui/transfer-table-bridge/d-table.directive.js new file mode 100644 index 0000000..de48adc --- /dev/null +++ b/gbpui/static/dashboard/gbpui/transfer-table-bridge/d-table.directive.js @@ -0,0 +1,91 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +(function () { + angular + .module('gbpui.transfer-table-bridge') + .directive('dTable', ['gbpui.basePath', function(basePath){ + return { + restrict: 'E', + scope: true, + templateUrl: basePath + + "transfer-table-bridge/transfer-table-bridge.html", + transclude: true, + link: function($scope, $elem, $attrs, $ctrl, $transclude) { + + var initial = []; + var available = []; + + var transcluded = $transclude(); + + transcluded.each(function(index, element) { + if(element.localName=="option") { + var val = { + 'id': $(element).attr('value'), + 'name': $(element).text() + }; + available.push(val); + + if($(element).prop('selected')) { + initial.push(val); + } + } + }); + $scope.initial = initial; + + var allocated = []; + + $scope.tableData = { + available: available, + allocated: allocated, + displayedAvailable: [], + displayedAllocated: [], + minItems: -1 + }; + + var maxAllocation = "maxItems" in $attrs + ? Number($attrs["maxItems"]) + : -1; + $scope.tableLimits = { + maxAllocation: maxAllocation + }; + + $scope.tableHelpText = { + allocHelpText: $attrs['allocatedHelpText'], + availHelpText: $attrs['availableHelpText'], + noAllocText: $attrs['noAllocatedText'], + noAvailText: $attrs['noAvailableText'] + }; + + $scope.facets = [{ + label: gettext("Name"), + name: "name", + singleton: true + }]; + + if("addItemLink" in $attrs) { + $scope.addItemLink = $attrs["addItemLink"]; + } + + if("allocatedFilter" in $attrs) { + $scope.allocatedFilter = true; + } + + $scope.id = $attrs["id"]; + $scope.name = $attrs["name"]; + + } + } + }]) + +})(); \ No newline at end of file diff --git a/gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table-bridge.html b/gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table-bridge.html new file mode 100644 index 0000000..f98369d --- /dev/null +++ b/gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table-bridge.html @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + +
+ +
Name
+
+ {$ ::tableHelpText.noAllocText $} +
+
+ {$ row.name $} + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
Name
+
+ {$ ::tableHelpText.noAvailText $} +
+
{$ row.name $} + + + + + + +
+ +
+ +
+
+ +
diff --git a/gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table.module.js b/gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table.module.js new file mode 100644 index 0000000..b56c38e --- /dev/null +++ b/gbpui/static/dashboard/gbpui/transfer-table-bridge/transfer-table.module.js @@ -0,0 +1,17 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +(function () { + angular + .module('gbpui.transfer-table-bridge', ['horizon.app.core.workflow']); +})(); \ No newline at end of file