Merge "Replaces multi select combos with transfer tables"
This commit is contained in:
commit
84cac65360
|
@ -14,3 +14,6 @@ ADD_INSTALLED_APPS = ['gbpui', ]
|
||||||
PANEL_GROUP = 'GroupPolicyPanels'
|
PANEL_GROUP = 'GroupPolicyPanels'
|
||||||
PANEL_GROUP_NAME = 'Policy'
|
PANEL_GROUP_NAME = 'Policy'
|
||||||
PANEL_GROUP_DASHBOARD = 'project'
|
PANEL_GROUP_DASHBOARD = 'project'
|
||||||
|
|
||||||
|
AUTO_DISCOVER_STATIC_FILES = True
|
||||||
|
ADD_ANGULAR_MODULES = ['gbpui', ]
|
||||||
|
|
|
@ -16,6 +16,11 @@ from django.forms import TextInput
|
||||||
from django.forms import widgets
|
from django.forms import widgets
|
||||||
from django.utils.safestring import mark_safe
|
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):
|
class DynamicMultiSelectWidget(widgets.SelectMultiple):
|
||||||
|
|
||||||
|
@ -84,3 +89,78 @@ class DropdownEditWidget(TextInput):
|
||||||
data_list += '<option value="%s">' % item
|
data_list += '<option value="%s">' % item
|
||||||
data_list += '</datalist>'
|
data_list += '</datalist>'
|
||||||
return mark_safe(text_html + data_list)
|
return mark_safe(text_html + data_list)
|
||||||
|
|
||||||
|
|
||||||
|
class TransferTableWidget(widgets.SelectMultiple):
|
||||||
|
actions_list = []
|
||||||
|
add_item_link = None
|
||||||
|
max_items = None
|
||||||
|
allocated_filter = False
|
||||||
|
|
||||||
|
allocated_help_text = None
|
||||||
|
available_help_text = None
|
||||||
|
no_allocated_text = None
|
||||||
|
no_available_text = None
|
||||||
|
|
||||||
|
def render(self, name, value, attrs=None, choices=()):
|
||||||
|
# css class currently breaks the layout for some reason,
|
||||||
|
self.attrs.pop('class', None)
|
||||||
|
|
||||||
|
final_attrs = self.build_attrs(attrs, name=name)
|
||||||
|
|
||||||
|
selected = [] if value is None else value
|
||||||
|
|
||||||
|
options = self.render_options(choices, selected)
|
||||||
|
|
||||||
|
if self.add_item_link is not None:
|
||||||
|
final_attrs['add_item_link'] = urlresolvers.reverse(
|
||||||
|
self.add_item_link
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.max_items is not None:
|
||||||
|
final_attrs['max_items'] = self.max_items
|
||||||
|
|
||||||
|
if self.allocated_filter:
|
||||||
|
final_attrs['allocated_filter'] = "True"
|
||||||
|
|
||||||
|
final_attrs['allocated_help_text'] = self.allocated_help_text
|
||||||
|
final_attrs['available_help_text'] = self.available_help_text
|
||||||
|
final_attrs['no_allocated_text'] = self.no_allocated_text
|
||||||
|
final_attrs['no_available_text'] = self.no_available_text
|
||||||
|
|
||||||
|
open_tag = format_html('<d-table {}>', flatatt(final_attrs))
|
||||||
|
|
||||||
|
output = [open_tag, options, '</d-table>']
|
||||||
|
|
||||||
|
return mark_safe('\n'.join(output))
|
||||||
|
|
||||||
|
# ...this adds the 'add item button' just by existing and returning a
|
||||||
|
# true-y value
|
||||||
|
def get_add_item_url(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class TransferTableField(fields.MultipleChoiceField):
|
||||||
|
widget = TransferTableWidget
|
||||||
|
|
||||||
|
def __init__(self, add_item_link=None, max_items=-1,
|
||||||
|
allocated_filter=False,
|
||||||
|
allocated_help_text="",
|
||||||
|
available_help_text="",
|
||||||
|
no_allocated_text=_("Select items from bellow"),
|
||||||
|
no_available_text=_("No available items"),
|
||||||
|
*args, **kwargs):
|
||||||
|
super(TransferTableField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.widget.add_item_link = add_item_link
|
||||||
|
self.widget.max_items = max_items
|
||||||
|
self.widget.allocated_filter = allocated_filter
|
||||||
|
|
||||||
|
self.widget.allocated_help_text = allocated_help_text
|
||||||
|
self.widget.available_help_text = available_help_text
|
||||||
|
|
||||||
|
self.widget.no_allocated_text = no_allocated_text
|
||||||
|
self.widget.no_available_text = no_available_text
|
||||||
|
|
||||||
|
def validate(self, *args, **kwargs):
|
||||||
|
return True
|
||||||
|
|
|
@ -55,7 +55,7 @@ class BaseUpdateForm(forms.SelfHandlingForm):
|
||||||
class UpdatePolicyRuleSetForm(BaseUpdateForm):
|
class UpdatePolicyRuleSetForm(BaseUpdateForm):
|
||||||
name = forms.CharField(label=_("Name"))
|
name = forms.CharField(label=_("Name"))
|
||||||
description = forms.CharField(label=_("Description"), required=False)
|
description = forms.CharField(label=_("Description"), required=False)
|
||||||
policy_rules = forms.MultipleChoiceField(label=_("Policy Rules"),)
|
policy_rules = fields.TransferTableField(label=_("Policy Rules"), )
|
||||||
shared = forms.BooleanField(label=_("Shared"), required=False)
|
shared = forms.BooleanField(label=_("Shared"), required=False)
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
@ -298,7 +298,11 @@ class UpdatePolicyRuleForm(BaseUpdateForm):
|
||||||
name = forms.CharField(max_length=80, label=_("Name"), required=False)
|
name = forms.CharField(max_length=80, label=_("Name"), required=False)
|
||||||
description = forms.CharField(label=_("Description"), required=False)
|
description = forms.CharField(label=_("Description"), required=False)
|
||||||
policy_classifier_id = forms.ChoiceField(label=_("Policy Classifier"))
|
policy_classifier_id = forms.ChoiceField(label=_("Policy Classifier"))
|
||||||
policy_actions = forms.MultipleChoiceField(label=_("Policy Actions"))
|
policy_actions = fields.TransferTableField(
|
||||||
|
label=_("Policy Actions"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
shared = forms.BooleanField(label=_("Shared"), required=False)
|
shared = forms.BooleanField(label=_("Shared"), required=False)
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
@ -306,17 +310,19 @@ class UpdatePolicyRuleForm(BaseUpdateForm):
|
||||||
try:
|
try:
|
||||||
policyrule_id = self.initial['policyrule_id']
|
policyrule_id = self.initial['policyrule_id']
|
||||||
rule = client.policyrule_get(request, policyrule_id)
|
rule = client.policyrule_get(request, policyrule_id)
|
||||||
|
|
||||||
for item in ['name', 'description',
|
for item in ['name', 'description',
|
||||||
'policy_classifier_id', 'policy_actions', 'shared']:
|
'policy_classifier_id', 'policy_actions', 'shared']:
|
||||||
self.fields[item].initial = getattr(rule, item)
|
self.fields[item].initial = getattr(rule, item)
|
||||||
|
|
||||||
actions = client.policyaction_list(request,
|
actions = client.policyaction_list(request,
|
||||||
tenant_id=request.user.tenant_id)
|
tenant_id=request.user.tenant_id)
|
||||||
action_list = [a.id for a in actions]
|
|
||||||
for action in actions:
|
for action in actions:
|
||||||
action.set_id_as_name_if_empty()
|
action.set_id_as_name_if_empty()
|
||||||
actions = sorted(actions, key=lambda action: action.name)
|
actions = sorted(actions, key=lambda action: action.name)
|
||||||
action_list = [(a.id, a.name) for a in actions]
|
action_list = [(a.id, a.name) for a in actions]
|
||||||
self.fields['policy_actions'].choices = action_list
|
self.fields['policy_actions'].choices = action_list
|
||||||
|
|
||||||
classifiers = client.policyclassifier_list(request,
|
classifiers = client.policyclassifier_list(request,
|
||||||
tenant_id=request.user.tenant_id)
|
tenant_id=request.user.tenant_id)
|
||||||
classifier_list = [(c.id, c.name) for c in classifiers]
|
classifier_list = [(c.id, c.name) for c in classifiers]
|
||||||
|
|
|
@ -21,6 +21,7 @@ from horizon import workflows
|
||||||
from gbpui import client
|
from gbpui import client
|
||||||
from gbpui import fields
|
from gbpui import fields
|
||||||
|
|
||||||
|
|
||||||
ADD_POLICY_ACTION_URL = "horizon:project:application_policy:addpolicyaction"
|
ADD_POLICY_ACTION_URL = "horizon:project:application_policy:addpolicyaction"
|
||||||
ADD_POLICY_CLASSIFIER_URL = "horizon:project:application_policy:"
|
ADD_POLICY_CLASSIFIER_URL = "horizon:project:application_policy:"
|
||||||
ADD_POLICY_CLASSIFIER_URL = ADD_POLICY_CLASSIFIER_URL + "addpolicyclassifier"
|
ADD_POLICY_CLASSIFIER_URL = ADD_POLICY_CLASSIFIER_URL + "addpolicyclassifier"
|
||||||
|
@ -28,11 +29,12 @@ ADD_POLICY_RULE_URL = "horizon:project:application_policy:addpolicyrule"
|
||||||
|
|
||||||
|
|
||||||
class SelectPolicyRuleAction(workflows.Action):
|
class SelectPolicyRuleAction(workflows.Action):
|
||||||
policy_rules = fields.DynamicMultiChoiceField(
|
policy_rules = fields.TransferTableField(
|
||||||
label=_("Policy Rules"),
|
label=_("Policy Rules"),
|
||||||
required=False,
|
required=False,
|
||||||
add_item_link=ADD_POLICY_RULE_URL,
|
add_item_link=ADD_POLICY_RULE_URL,
|
||||||
help_text=_("Create a policy rule set with selected rules."))
|
help_text=_("Create a policy rule set with selected rules.")
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = _("Rules")
|
name = _("Rules")
|
||||||
|
@ -162,11 +164,17 @@ class SelectPolicyClassifierAction(workflows.Action):
|
||||||
|
|
||||||
|
|
||||||
class SelectPolicyActionAction(workflows.Action):
|
class SelectPolicyActionAction(workflows.Action):
|
||||||
actions = fields.DynamicMultiChoiceField(
|
actions = fields.TransferTableField(
|
||||||
label=_("Policy Action"),
|
label=_("Policy Action"),
|
||||||
required=False,
|
required=False,
|
||||||
help_text=_("Create a policy-rule with selected action."),
|
add_item_link=ADD_POLICY_ACTION_URL,
|
||||||
add_item_link=ADD_POLICY_ACTION_URL)
|
help_text=_("Create a policy-rule with selected action.")
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, request, context, *args, **kwargs):
|
||||||
|
super(SelectPolicyActionAction, self).__init__(
|
||||||
|
request, context, *args, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = _("actions")
|
name = _("actions")
|
||||||
|
@ -176,14 +184,11 @@ class SelectPolicyActionAction(workflows.Action):
|
||||||
try:
|
try:
|
||||||
actions = client.policyaction_list(request,
|
actions = client.policyaction_list(request,
|
||||||
tenant_id=request.user.tenant_id)
|
tenant_id=request.user.tenant_id)
|
||||||
action_list = [a.id for a in actions]
|
|
||||||
for action in actions:
|
for action in actions:
|
||||||
action.set_id_as_name_if_empty()
|
action.set_id_as_name_if_empty()
|
||||||
actions = sorted(actions,
|
actions = sorted(actions,
|
||||||
key=lambda action: action.name)
|
key=lambda action: action.name)
|
||||||
action_list = [(a.id, a.name) for a in actions]
|
action_list = [(a.id, a.name) for a in actions]
|
||||||
if len(action_list) > 0:
|
|
||||||
self.fields['actions'].initial = action_list[0]
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
action_list = []
|
action_list = []
|
||||||
exceptions.handle(request,
|
exceptions.handle(request,
|
||||||
|
|
|
@ -63,10 +63,11 @@ class AddL3PolicyForm(forms.SelfHandlingForm):
|
||||||
label=_("Subnet Prefix Length"),
|
label=_("Subnet Prefix Length"),
|
||||||
help_text=_("Between 2 - 30 for IP4"
|
help_text=_("Between 2 - 30 for IP4"
|
||||||
"and 2-127 for IP6."),)
|
"and 2-127 for IP6."),)
|
||||||
external_segments = \
|
external_segments = fields.TransferTableField(
|
||||||
fields.CustomMultiChoiceField(label=_("External Segments"),
|
label=_("External Segments"),
|
||||||
add_item_link=EXT_SEG_PARAM_URL,
|
add_item_link=EXT_SEG_PARAM_URL,
|
||||||
required=False)
|
required=False
|
||||||
|
)
|
||||||
shared = forms.BooleanField(label=_("Shared"),
|
shared = forms.BooleanField(label=_("Shared"),
|
||||||
initial=False,
|
initial=False,
|
||||||
required=False)
|
required=False)
|
||||||
|
@ -296,9 +297,11 @@ class CreateServicePolicyForm(forms.SelfHandlingForm):
|
||||||
name = forms.CharField(max_length=80, label=_("Name"))
|
name = forms.CharField(max_length=80, label=_("Name"))
|
||||||
description = forms.CharField(
|
description = forms.CharField(
|
||||||
max_length=80, label=_("Description"), required=False)
|
max_length=80, label=_("Description"), required=False)
|
||||||
network_service_params = fields.CustomMultiChoiceField(label=_(
|
network_service_params = fields.TransferTableField(
|
||||||
"Network Service Parameters"), add_item_link=NETWORK_PARAM_URL,
|
label=_("Network Service Parameters"),
|
||||||
required=False)
|
add_item_link=NETWORK_PARAM_URL,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
shared = forms.BooleanField(label=_("Shared"),
|
shared = forms.BooleanField(label=_("Shared"),
|
||||||
initial=False, required=False)
|
initial=False, required=False)
|
||||||
|
|
||||||
|
@ -555,9 +558,11 @@ class CreateExternalConnectivityForm(forms.SelfHandlingForm):
|
||||||
"(e.g. 192.168.0.0/24,"
|
"(e.g. 192.168.0.0/24,"
|
||||||
"2001:DB8::/48)"),
|
"2001:DB8::/48)"),
|
||||||
version=forms.IPv4 | forms.IPv6, mask=True)
|
version=forms.IPv4 | forms.IPv6, mask=True)
|
||||||
external_routes = fields.CustomMultiChoiceField(
|
external_routes = fields.TransferTableField(
|
||||||
label=_("External Routes"), add_item_link=ROUTE_URL,
|
label=_("External Routes"),
|
||||||
required=False)
|
add_item_link=ROUTE_URL,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
subnet_id = forms.ChoiceField(label=_("Subnet ID"), required=False)
|
subnet_id = forms.ChoiceField(label=_("Subnet ID"), required=False)
|
||||||
port_address_translation = forms.BooleanField(
|
port_address_translation = forms.BooleanField(
|
||||||
label=_("Port Address Translation"),
|
label=_("Port Address Translation"),
|
||||||
|
|
|
@ -22,6 +22,7 @@ from horizon import forms
|
||||||
from horizon import messages
|
from horizon import messages
|
||||||
|
|
||||||
from gbpui import client
|
from gbpui import client
|
||||||
|
from gbpui import fields
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -31,10 +32,12 @@ class UpdatePolicyTargetForm(forms.SelfHandlingForm):
|
||||||
label=_("Name"), required=False)
|
label=_("Name"), required=False)
|
||||||
description = forms.CharField(max_length=80,
|
description = forms.CharField(max_length=80,
|
||||||
label=_("Description"), required=False)
|
label=_("Description"), required=False)
|
||||||
provided_policy_rule_sets = forms.MultipleChoiceField(
|
provided_policy_rule_sets = fields.TransferTableField(
|
||||||
label=_("Provided Policy Rule Set"), required=False)
|
label=_("Provided Policy Rule Set"), required=False
|
||||||
consumed_policy_rule_sets = forms.MultipleChoiceField(
|
)
|
||||||
label=_("Consumed Policy Rule Set"), required=False)
|
consumed_policy_rule_sets = fields.TransferTableField(
|
||||||
|
label=_("Consumed Policy Rule Set"), required=False
|
||||||
|
)
|
||||||
l2_policy_id = forms.ChoiceField(
|
l2_policy_id = forms.ChoiceField(
|
||||||
label=_("Network Policy"),
|
label=_("Network Policy"),
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -141,9 +144,9 @@ class UpdateExternalPolicyTargetForm(forms.SelfHandlingForm):
|
||||||
label=_("Name"), required=False)
|
label=_("Name"), required=False)
|
||||||
description = forms.CharField(max_length=80,
|
description = forms.CharField(max_length=80,
|
||||||
label=_("Description"), required=False)
|
label=_("Description"), required=False)
|
||||||
provided_policy_rule_sets = forms.MultipleChoiceField(
|
provided_policy_rule_sets = fields.TransferTableField(
|
||||||
label=_("Provided Policy Rule Set"), required=False)
|
label=_("Provided Policy Rule Set"), required=False)
|
||||||
consumed_policy_rule_sets = forms.MultipleChoiceField(
|
consumed_policy_rule_sets = fields.TransferTableField(
|
||||||
label=_("Consumed Policy Rule Set"), required=False)
|
label=_("Consumed Policy Rule Set"), required=False)
|
||||||
external_segments = forms.MultipleChoiceField(
|
external_segments = forms.MultipleChoiceField(
|
||||||
label=_("External Connectivity"), required=True,
|
label=_("External Connectivity"), required=True,
|
||||||
|
|
|
@ -48,12 +48,12 @@ ADD_EXTERNAL_CONNECTIVITY = \
|
||||||
|
|
||||||
|
|
||||||
class SelectPolicyRuleSetAction(workflows.Action):
|
class SelectPolicyRuleSetAction(workflows.Action):
|
||||||
provided_policy_rule_set = fields.DynamicMultiChoiceField(
|
provided_policy_rule_set = fields.TransferTableField(
|
||||||
label=_("Provided Policy Rule Set"),
|
label=_("Provided Policy Rule Set"),
|
||||||
help_text=_("Choose a policy rule set for an Group."),
|
help_text=_("Choose a policy rule set for an Group."),
|
||||||
add_item_link=POLICY_RULE_SET_URL,
|
add_item_link=POLICY_RULE_SET_URL,
|
||||||
required=False)
|
required=False)
|
||||||
consumed_policy_rule_set = fields.DynamicMultiChoiceField(
|
consumed_policy_rule_set = fields.TransferTableField(
|
||||||
label=_("Consumed Policy Rule Set"),
|
label=_("Consumed Policy Rule Set"),
|
||||||
help_text=_("Select consumed policy rule set for Group."),
|
help_text=_("Select consumed policy rule set for Group."),
|
||||||
add_item_link=POLICY_RULE_SET_URL,
|
add_item_link=POLICY_RULE_SET_URL,
|
||||||
|
@ -64,8 +64,10 @@ class SelectPolicyRuleSetAction(workflows.Action):
|
||||||
help_text = _("Select Policy Rule Set for Group.")
|
help_text = _("Select Policy Rule Set for Group.")
|
||||||
|
|
||||||
def _policy_rule_set_list(self, request):
|
def _policy_rule_set_list(self, request):
|
||||||
policy_rule_sets = client.policy_rule_set_list(request,
|
policy_rule_sets = client.policy_rule_set_list(
|
||||||
tenant_id=request.user.tenant_id)
|
request,
|
||||||
|
tenant_id=request.user.tenant_id
|
||||||
|
)
|
||||||
for c in policy_rule_sets:
|
for c in policy_rule_sets:
|
||||||
c.set_id_as_name_if_empty()
|
c.set_id_as_name_if_empty()
|
||||||
policy_rule_sets = sorted(policy_rule_sets,
|
policy_rule_sets = sorted(policy_rule_sets,
|
||||||
|
@ -75,12 +77,8 @@ class SelectPolicyRuleSetAction(workflows.Action):
|
||||||
def populate_provided_policy_rule_set_choices(self, request, context):
|
def populate_provided_policy_rule_set_choices(self, request, context):
|
||||||
policy_rule_set_list = []
|
policy_rule_set_list = []
|
||||||
try:
|
try:
|
||||||
rsets = self._policy_rule_set_list(request)
|
policy_rule_set_list = self._policy_rule_set_list(request)
|
||||||
if len(rsets) == 0:
|
|
||||||
rsets.extend([('None', 'No Provided Policy Rule Sets')])
|
|
||||||
policy_rule_set_list = rsets
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
policy_rule_set_list = []
|
|
||||||
msg = _('Unable to retrieve policy rule set. %s.') % (str(e))
|
msg = _('Unable to retrieve policy rule set. %s.') % (str(e))
|
||||||
exceptions.handle(request, msg)
|
exceptions.handle(request, msg)
|
||||||
return policy_rule_set_list
|
return policy_rule_set_list
|
||||||
|
@ -88,9 +86,7 @@ class SelectPolicyRuleSetAction(workflows.Action):
|
||||||
def populate_consumed_policy_rule_set_choices(self, request, context):
|
def populate_consumed_policy_rule_set_choices(self, request, context):
|
||||||
policy_rule_set_list = []
|
policy_rule_set_list = []
|
||||||
try:
|
try:
|
||||||
policy_rule_set_list = [('None', 'No Consumed Policy Rule Sets')]
|
policy_rule_set_list = self._policy_rule_set_list(request)
|
||||||
policy_rule_set_list =\
|
|
||||||
self._policy_rule_set_list(request)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = _('Unable to retrieve policy rule set. %s.') % (str(e))
|
msg = _('Unable to retrieve policy rule set. %s.') % (str(e))
|
||||||
exceptions.handle(request, msg)
|
exceptions.handle(request, msg)
|
||||||
|
@ -342,6 +338,7 @@ class SetAccessControlsAction(workflows.Action):
|
||||||
help_text=_("Key pair to use for "
|
help_text=_("Key pair to use for "
|
||||||
"authentication."),
|
"authentication."),
|
||||||
add_item_link=KEYPAIR_IMPORT_URL)
|
add_item_link=KEYPAIR_IMPORT_URL)
|
||||||
|
|
||||||
admin_pass = forms.RegexField(
|
admin_pass = forms.RegexField(
|
||||||
label=_("Admin Password"),
|
label=_("Admin Password"),
|
||||||
required=False,
|
required=False,
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* 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', ['gbpui.transfer-table-bridge'])
|
||||||
|
.config(module_config);
|
||||||
|
|
||||||
|
module_config.$inject = ["$provide","$windowProvider"];
|
||||||
|
|
||||||
|
function module_config($provide, $windowProvider) {
|
||||||
|
var path = $windowProvider.$get().STATIC_URL + 'dashboard/gbpui/';
|
||||||
|
$provide.constant('gbpui.basePath', path);
|
||||||
|
}
|
||||||
|
})();
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* 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('dSelect', function () {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
scope: true,
|
||||||
|
link: function ($scope, $elem, $attrs, $ctrl) {
|
||||||
|
|
||||||
|
|
||||||
|
$.each($scope.tableData.available, function (index, optionObject) {
|
||||||
|
var option = $("<option></option>");
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
|
@ -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"];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,114 @@
|
||||||
|
<transfer-table tr-model="tableData" limits="tableLimits" help-text="tableHelpText">
|
||||||
|
|
||||||
|
<allocated ng-model="tableData.allocated.length">
|
||||||
|
<table st-table="tableData.displayedAllocated"
|
||||||
|
st-safe-src="tableData.allocated"
|
||||||
|
hz-table
|
||||||
|
class="table table-striped table-rsp table-detail table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr ng-if="allocatedFilter">
|
||||||
|
<th colspan="2">
|
||||||
|
<hz-magic-search-bar filter-facets="facets"></hz-magic-search-bar>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th colspan="2">Name</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-if="tableData.allocated.length === 0">
|
||||||
|
<td colspan="{{ addItemLink ? 2 : 1 }}">
|
||||||
|
<div class="no-rows-help">
|
||||||
|
{$ ::tableHelpText.noAllocText $}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr ng-repeat="row in tableData.displayedAllocated track by row.id">
|
||||||
|
<td>
|
||||||
|
{$ row.name $}
|
||||||
|
</td>
|
||||||
|
<td class="actions_column">
|
||||||
|
<action-list>
|
||||||
|
<button tabIndex="0"
|
||||||
|
ng-class="'btn btn-default'"
|
||||||
|
ng-click="trCtrl.deallocate(row)"
|
||||||
|
type="button">
|
||||||
|
<span class="fa fa-arrow-down"></span>
|
||||||
|
</button>
|
||||||
|
</action-list>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</allocated>
|
||||||
|
|
||||||
|
<available>
|
||||||
|
<table
|
||||||
|
st-table="tableData.displayedAvailable"
|
||||||
|
st-safe-src="tableData.available"
|
||||||
|
hz-table
|
||||||
|
class="table table-striped table-rsp table-detail table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="{$ addItemLink ? 1 : 2 $}">
|
||||||
|
<hz-magic-search-bar filter-facets="facets"></hz-magic-search-bar>
|
||||||
|
</th>
|
||||||
|
<th ng-if="addItemLink">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<a href="{$ addItemLink $}" data-add-to-field="{$ id $}_select" class="btn btn-default ajax-add ajax-modal">
|
||||||
|
<span class="fa fa-plus"></span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th colspan="2">Name</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr ng-if="trCtrl.numAvailable() === 0">
|
||||||
|
<td colspan="{{ addItemLink ? 2 : 1 }}">
|
||||||
|
<div class="no-rows-help">
|
||||||
|
{$ ::tableHelpText.noAvailText $}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr ng-repeat="row in tableData.displayedAvailable track by row.id"
|
||||||
|
ng-if="!trCtrl.allocatedIds[row.id]"
|
||||||
|
>
|
||||||
|
<td>{$ row.name $}</td>
|
||||||
|
<td class="actions_column">
|
||||||
|
<action-list button-tooltip="row.warningMessage"
|
||||||
|
bt-model="ctrl.tooltipModel"
|
||||||
|
bt-disabled="!row.disabled"
|
||||||
|
warning-classes="'invalid'">
|
||||||
|
<notifications>
|
||||||
|
<span class="fa fa-exclamation-circle invalid"
|
||||||
|
ng-show="row.disabled"></span>
|
||||||
|
</notifications>
|
||||||
|
<button tabIndex="0"
|
||||||
|
ng-class="'btn btn-default'"
|
||||||
|
ng-click="trCtrl.allocate(row)"
|
||||||
|
type="button">
|
||||||
|
<span class="fa fa-arrow-up"></span>
|
||||||
|
</button>
|
||||||
|
</action-list>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div style="display:None">
|
||||||
|
<select
|
||||||
|
d-select
|
||||||
|
id="{$ id $}_select"
|
||||||
|
data-add-item-url
|
||||||
|
multiple
|
||||||
|
name="{$ name $}" >
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</available>
|
||||||
|
|
||||||
|
</transfer-table>
|
|
@ -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']);
|
||||||
|
})();
|
Loading…
Reference in New Issue