mirror of
https://github.com/ansible/awx.git
synced 2026-01-14 03:10:42 -03:30
Merge branch 'master' into pg9.4-unstable
Conflicts: setup/roles/packages_ubuntu/vars/Ubuntu-14.04.yml
This commit is contained in:
commit
7ccc49ebe3
15
Makefile
15
Makefile
@ -199,10 +199,12 @@ server_noattach:
|
||||
tmux rename-window 'Tower'
|
||||
tmux select-window -t tower:0
|
||||
tmux split-window -v 'exec make celeryd'
|
||||
tmux split-window -h 'exec make socketservice'
|
||||
tmux select-pane -U
|
||||
tmux split-window -v 'exec make receiver'
|
||||
tmux split-window -h 'exec make taskmanager'
|
||||
tmux new-window 'exec make receiver'
|
||||
tmux select-window -t tower:1
|
||||
tmux rename-window 'Extra Services'
|
||||
tmux split-window -v 'exec make socketservice'
|
||||
tmux split-window -h 'exec make factcacher'
|
||||
|
||||
server: server_noattach
|
||||
tmux -2 attach-session -t tower
|
||||
@ -229,6 +231,9 @@ taskmanager:
|
||||
socketservice:
|
||||
$(PYTHON) manage.py run_socketio_service
|
||||
|
||||
factcacher:
|
||||
$(PYTHON) manage.py run_fact_cache_receiver
|
||||
|
||||
pep8:
|
||||
pep8 -r awx/
|
||||
|
||||
@ -255,7 +260,7 @@ ui_analysis_report: reports/ui_code node_modules Gruntfile.js
|
||||
|
||||
reports/ui_code: node_modules clean-ui Brocfile.js bower.json Gruntfile.js
|
||||
rm -rf reports/ui_code
|
||||
$(BROCCOLI) build reports/ui_code -- --no-concat --no-tests --no-styles
|
||||
$(BROCCOLI) build reports/ui_code -- --no-concat --no-tests --no-styles --no-sourcemaps
|
||||
|
||||
# Run UI unit tests
|
||||
test_ui: node_modules minjs_ci Gruntfile.js
|
||||
@ -294,7 +299,7 @@ devjs: node_modules clean-ui Brocfile.js bower.json Gruntfile.js
|
||||
|
||||
# Build minified JS/CSS.
|
||||
minjs: node_modules clean-ui Brocfile.js
|
||||
$(BROCCOLI) build awx/ui/dist -- --silent --no-debug --no-tests --compress --no-docs
|
||||
$(BROCCOLI) build awx/ui/dist -- --silent --no-debug --no-tests --compress --no-docs --no-sourcemaps
|
||||
|
||||
minjs_ci: node_modules clean-ui Brocfile.js
|
||||
$(BROCCOLI) build awx/ui/dist -- --no-debug --compress --no-docs
|
||||
|
||||
@ -365,7 +365,7 @@ class SubListCreateAPIView(SubListAPIView, ListCreateAPIView):
|
||||
data[parent_key] = self.kwargs['pk']
|
||||
|
||||
# attempt to deserialize the object
|
||||
serializer = self.serializer_class(data=data)
|
||||
serializer = self.get_serializer(data=data)
|
||||
if not serializer.is_valid():
|
||||
return Response(serializer.errors,
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -377,7 +377,7 @@ class SubListCreateAPIView(SubListAPIView, ListCreateAPIView):
|
||||
# save the object through the serializer, reload and returned the saved
|
||||
# object deserialized
|
||||
obj = serializer.save()
|
||||
serializer = self.serializer_class(obj)
|
||||
serializer = self.get_serializer(instance=obj)
|
||||
|
||||
headers = {'Location': obj.get_absolute_url()}
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||
|
||||
@ -6,6 +6,7 @@ import json
|
||||
import re
|
||||
import logging
|
||||
from dateutil import rrule
|
||||
from ast import literal_eval
|
||||
|
||||
# PyYAML
|
||||
import yaml
|
||||
@ -1294,6 +1295,16 @@ class CredentialSerializer(BaseSerializer):
|
||||
for field in Credential.PASSWORD_FIELDS:
|
||||
if unicode(attrs.get(field, '')).startswith('$encrypted$'):
|
||||
attrs.pop(field, None)
|
||||
|
||||
# If creating a credential from a view that automatically sets the
|
||||
# parent_key (user or team), set the other value to None.
|
||||
view = self.context.get('view', None)
|
||||
parent_key = getattr(view, 'parent_key', None)
|
||||
if parent_key == 'user':
|
||||
attrs['team'] = None
|
||||
if parent_key == 'team':
|
||||
attrs['user'] = None
|
||||
|
||||
instance = super(CredentialSerializer, self).restore_object(attrs, instance)
|
||||
return instance
|
||||
|
||||
@ -1690,6 +1701,93 @@ class AdHocCommandEventSerializer(BaseSerializer):
|
||||
res['host'] = reverse('api:host_detail', args=(obj.host.pk,))
|
||||
return res
|
||||
|
||||
class JobLaunchSerializer(BaseSerializer):
|
||||
passwords_needed_to_start = serializers.Field(source='passwords_needed_to_start')
|
||||
can_start_without_user_input = serializers.Field(source='can_start_without_user_input')
|
||||
variables_needed_to_start = serializers.Field(source='variables_needed_to_start')
|
||||
credential_needed_to_start = serializers.SerializerMethodField('get_credential_needed_to_start')
|
||||
survey_enabled = serializers.SerializerMethodField('get_survey_enabled')
|
||||
|
||||
class Meta:
|
||||
model = JobTemplate
|
||||
fields = ('can_start_without_user_input', 'passwords_needed_to_start', 'extra_vars',
|
||||
'ask_variables_on_launch', 'survey_enabled', 'variables_needed_to_start',
|
||||
'credential', 'credential_needed_to_start',)
|
||||
read_only_fields = ('ask_variables_on_launch',)
|
||||
write_only_fields = ('credential','extra_vars',)
|
||||
|
||||
def to_native(self, obj):
|
||||
res = super(JobLaunchSerializer, self).to_native(obj)
|
||||
view = self.context.get('view', None)
|
||||
if obj and hasattr(view, '_raw_data_form_marker'):
|
||||
if obj.passwords_needed_to_start:
|
||||
password_keys = dict([(p, u'') for p in obj.passwords_needed_to_start])
|
||||
res.update(password_keys)
|
||||
if self.get_credential_needed_to_start(obj) is True:
|
||||
res.update(dict(credential=''))
|
||||
return res
|
||||
|
||||
def get_credential_needed_to_start(self, obj):
|
||||
return not (obj and obj.credential and obj.credential.active)
|
||||
|
||||
def get_survey_enabled(self, obj):
|
||||
if obj:
|
||||
return obj.survey_enabled and 'spec' in obj.survey_spec
|
||||
return False
|
||||
|
||||
def validate_credential(self, attrs, source):
|
||||
obj = self.context.get('obj')
|
||||
credential = attrs.get(source, None) or (obj and obj.credential)
|
||||
if not credential or not credential.active:
|
||||
raise serializers.ValidationError('Credential not provided')
|
||||
attrs[source] = credential
|
||||
return attrs
|
||||
|
||||
def validate_passwords_needed_to_start(self, attrs, source):
|
||||
obj = self.context.get('obj')
|
||||
passwords = self.context.get('passwords')
|
||||
data = self.context.get('data')
|
||||
|
||||
# fill passwords dict with request data passwords
|
||||
if obj.passwords_needed_to_start:
|
||||
try:
|
||||
for p in obj.passwords_needed_to_start:
|
||||
passwords[p] = data.get(p)
|
||||
except KeyError:
|
||||
raise serializers.ValidationError(obj.passwords_needed_to_start)
|
||||
return attrs
|
||||
|
||||
def validate_extra_vars(self, attrs, source):
|
||||
extra_vars = attrs.get(source, {})
|
||||
if not extra_vars:
|
||||
return attrs
|
||||
|
||||
try:
|
||||
extra_vars = literal_eval(extra_vars)
|
||||
attrs['extra_vars'] = extra_vars
|
||||
except Exception:
|
||||
if not isinstance(extra_vars, dict):
|
||||
raise serializers.ValidationError("Invalid format. JSON expected.")
|
||||
return attrs
|
||||
|
||||
def validate_variables_needed_to_start(self, attrs, source):
|
||||
obj = self.context.get('obj')
|
||||
|
||||
if self.get_survey_enabled(obj):
|
||||
validation_errors = obj.survey_variable_validation(attrs.get('extra_vars', {}))
|
||||
if validation_errors:
|
||||
raise serializers.ValidationError(validation_errors)
|
||||
return attrs
|
||||
|
||||
def validate(self, attrs):
|
||||
obj = self.context.get('obj')
|
||||
|
||||
if obj.job_type != PERM_INVENTORY_SCAN and (obj.project is None or not obj.project.active):
|
||||
raise serializers.ValidationError(dict(errors=["Job Template Project is missing or undefined"]))
|
||||
if obj.inventory is None or not obj.inventory.active:
|
||||
raise serializers.ValidationError(dict(errors=["Job Template Inventory is missing or undefined"]))
|
||||
|
||||
return attrs
|
||||
|
||||
class ScheduleSerializer(BaseSerializer):
|
||||
|
||||
|
||||
@ -14,16 +14,16 @@
|
||||
.ansi4 { text-decoration: underline; }
|
||||
.ansi9 { text-decoration: line-through; }
|
||||
.ansi30 { color: #000316; }
|
||||
.ansi31 { color: #AA0000; }
|
||||
.ansi32 { color: #00AA00; }
|
||||
.ansi31 { color: #ff5850; }
|
||||
.ansi32 { color: #60D66F; }
|
||||
.ansi33 { color: #AA5500; }
|
||||
.ansi34 { color: #0000AA; }
|
||||
.ansi35 { color: #E850A8; }
|
||||
.ansi36 { color: #00AAAA; }
|
||||
.ansi37 { color: #F5F1DE; }
|
||||
.ansi40 { background-color: #000000; }
|
||||
.ansi41 { background-color: #AA0000; }
|
||||
.ansi42 { background-color: #00AA00; }
|
||||
.ansi41 { background-color: #ff5850; }
|
||||
.ansi42 { background-color: #60D66F; }
|
||||
.ansi43 { background-color: #AA5500; }
|
||||
.ansi44 { background-color: #0000AA; }
|
||||
.ansi45 { background-color: #E850A8; }
|
||||
|
||||
@ -1434,44 +1434,33 @@ class JobTemplateDetail(RetrieveUpdateDestroyAPIView):
|
||||
return super(JobTemplateDetail, self).destroy(request, *args, **kwargs)
|
||||
|
||||
|
||||
class JobTemplateLaunch(GenericAPIView):
|
||||
class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
|
||||
|
||||
model = JobTemplate
|
||||
# FIXME: Add serializer class to define fields in OPTIONS request!
|
||||
serializer_class = JobLaunchSerializer
|
||||
is_job_start = True
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
data = {}
|
||||
data['can_start_without_user_input'] = obj.can_start_without_user_input()
|
||||
data['passwords_needed_to_start'] = obj.passwords_needed_to_start
|
||||
data['ask_variables_on_launch'] = obj.ask_variables_on_launch
|
||||
data['variables_needed_to_start'] = obj.variables_needed_to_start
|
||||
data['credential_needed_to_start'] = obj.credential is None
|
||||
data['survey_enabled'] = obj.survey_enabled and 'spec' in obj.survey_spec
|
||||
return Response(data)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if not request.user.can_access(self.model, 'start', obj):
|
||||
raise PermissionDenied()
|
||||
if obj.survey_enabled and 'spec' in obj.survey_spec:
|
||||
if request.DATA == "":
|
||||
request_data = {}
|
||||
else:
|
||||
request_data = request.DATA
|
||||
validation_errors = obj.survey_variable_validation(request_data.get('extra_vars', {}))
|
||||
if validation_errors:
|
||||
return Response(dict(variables_needed_to_start=validation_errors),
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
if obj.credential is None and ('credential' not in request.DATA and 'credential_id' not in request.DATA):
|
||||
return Response(dict(errors="Credential not provided"), status=status.HTTP_400_BAD_REQUEST)
|
||||
if obj.job_type != PERM_INVENTORY_SCAN and (obj.project is None or not obj.project.active):
|
||||
return Response(dict(errors="Job Template Project is missing or undefined"), status=status.HTTP_400_BAD_REQUEST)
|
||||
if obj.inventory is None or not obj.inventory.active:
|
||||
return Response(dict(errors="Job Template Inventory is missing or undefined"), status=status.HTTP_400_BAD_REQUEST)
|
||||
new_job = obj.create_unified_job(**request.DATA)
|
||||
result = new_job.signal_start(**request.DATA)
|
||||
|
||||
if 'credential' not in request.DATA and 'credential_id' in request.DATA:
|
||||
request.DATA['credential'] = request.DATA['credential_id']
|
||||
|
||||
passwords = {}
|
||||
serializer = self.serializer_class(data=request.DATA, context={'obj': obj, 'data': request.DATA, 'passwords': passwords})
|
||||
if not serializer.is_valid():
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
kv = {
|
||||
'credential': serializer.object.credential.pk,
|
||||
'extra_vars': serializer.object.extra_vars
|
||||
}
|
||||
kv.update(passwords)
|
||||
|
||||
new_job = obj.create_unified_job(**kv)
|
||||
result = new_job.signal_start(**kv)
|
||||
if not result:
|
||||
data = dict(passwords_needed_to_start=new_job.passwords_needed_to_start)
|
||||
new_job.delete()
|
||||
|
||||
@ -205,6 +205,7 @@ class SocketIOHandler(WSGIHandler):
|
||||
del self.websocket.environ
|
||||
del self.websocket
|
||||
if self.environ:
|
||||
self.environ.pop('wsgi.websocket', None)
|
||||
del self.environ
|
||||
|
||||
def handle_bad_request(self):
|
||||
|
||||
@ -4,12 +4,12 @@
|
||||
# Python
|
||||
import re
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import datetime
|
||||
from optparse import make_option
|
||||
|
||||
# Django
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
from django.utils.timezone import now
|
||||
|
||||
# AWX
|
||||
from awx.fact.models.fact import * # noqa
|
||||
@ -30,20 +30,32 @@ class CleanupFacts(object):
|
||||
# pivot -= granularity
|
||||
# group by host
|
||||
def cleanup(self, older_than_abs, granularity):
|
||||
flag_delete_all = False
|
||||
fact_oldest = FactVersion.objects.all().order_by('timestamp').first()
|
||||
if not fact_oldest:
|
||||
return 0
|
||||
|
||||
# Special case, granularity=0x where x is d, w, or y
|
||||
# The intent is to delete all facts < older_than_abs
|
||||
if granularity == relativedelta():
|
||||
flag_delete_all = True
|
||||
|
||||
total = 0
|
||||
date_pivot = older_than_abs
|
||||
while date_pivot > fact_oldest.timestamp:
|
||||
date_pivot_next = date_pivot - granularity
|
||||
kv = {
|
||||
'timestamp__lte': date_pivot,
|
||||
'timestamp__gt': date_pivot_next,
|
||||
'timestamp__lte': date_pivot
|
||||
}
|
||||
if not flag_delete_all:
|
||||
kv['timestamp__gt'] = date_pivot_next
|
||||
|
||||
version_objs = FactVersion.objects.filter(**kv).order_by('-timestamp')
|
||||
|
||||
if flag_delete_all:
|
||||
total = version_objs.delete()
|
||||
break
|
||||
|
||||
# Transform array -> {host_id} = [<fact_version>, <fact_version>, ...]
|
||||
# TODO: If this set gets large then we can use mongo to transform the data set for us.
|
||||
host_ids = {}
|
||||
@ -66,13 +78,14 @@ class CleanupFacts(object):
|
||||
total += count
|
||||
|
||||
date_pivot = date_pivot_next
|
||||
|
||||
return total
|
||||
|
||||
'''
|
||||
older_than and granularity are of type relativedelta
|
||||
'''
|
||||
def run(self, older_than, granularity):
|
||||
t = datetime.now()
|
||||
t = now()
|
||||
deleted_count = self.cleanup(t - older_than, granularity)
|
||||
print("Deleted %d facts." % deleted_count)
|
||||
|
||||
|
||||
@ -357,8 +357,9 @@ class ExecutableJsonLoader(BaseLoader):
|
||||
stdout, stderr = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError('%r failed (rc=%d) with output: %s' % (cmd, proc.returncode, stderr))
|
||||
data = json.loads(stdout)
|
||||
if not isinstance(data, dict):
|
||||
try:
|
||||
data = json.loads(stdout)
|
||||
except ValueError:
|
||||
raise TypeError('Returned JSON must be a dictionary, got %s instead' % str(type(data)))
|
||||
except:
|
||||
logger.error('Failed to load JSON from: %s', stdout)
|
||||
|
||||
@ -29,7 +29,7 @@ valid_sockets = []
|
||||
class TowerBaseNamespace(BaseNamespace):
|
||||
|
||||
def get_allowed_methods(self):
|
||||
return []
|
||||
return ['recv_disconnect']
|
||||
|
||||
def get_initial_acl(self):
|
||||
global valid_sockets
|
||||
@ -99,7 +99,8 @@ class AdHocCommandEventNamespace(TowerBaseNamespace):
|
||||
class ScheduleNamespace(TowerBaseNamespace):
|
||||
|
||||
def get_allowed_methods(self):
|
||||
return ["schedule_changed"]
|
||||
parent_allowed = super(ScheduleNamespace, self).get_allowed_methods()
|
||||
return parent_allowed + ["schedule_changed"]
|
||||
|
||||
def recv_connect(self):
|
||||
logger.info("Received client connect for schedule namespace from %s" % str(self.environ['REMOTE_ADDR']))
|
||||
@ -131,7 +132,11 @@ def notification_handler(server):
|
||||
}
|
||||
for session_id, socket in list(server.sockets.iteritems()):
|
||||
if session_id in valid_sockets:
|
||||
socket.send_packet(packet)
|
||||
try:
|
||||
socket.send_packet(packet)
|
||||
except Exception, e:
|
||||
logger.error("Error sending client packet to %s: %s" % (str(session_id), str(packet)))
|
||||
logger.error("Error was: " + str(e))
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
'''
|
||||
|
||||
@ -379,6 +379,23 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
||||
# If update_fields has been specified, add our field names to it,
|
||||
# if hit hasn't been specified, then we're just doing a normal save.
|
||||
update_fields = kwargs.get('update_fields', [])
|
||||
# If updating a credential, make sure that we only allow user OR team
|
||||
# to be set, and clear out the other field based on which one has
|
||||
# changed.
|
||||
if self.pk:
|
||||
cred_before = Credential.objects.get(pk=self.pk)
|
||||
if self.user and self.team:
|
||||
# If the user changed, remove the previously assigned team.
|
||||
if cred_before.user != self.user:
|
||||
self.team = None
|
||||
if 'team' not in update_fields:
|
||||
update_fields.append('team')
|
||||
# If the team changed, remove the previously assigned user.
|
||||
elif cred_before.team != self.team:
|
||||
self.user = None
|
||||
if 'user' not in update_fields:
|
||||
update_fields.append('user')
|
||||
# Set cloud flag based on credential kind.
|
||||
cloud = self.kind in CLOUD_PROVIDERS + ('aws',)
|
||||
if self.cloud != cloud:
|
||||
self.cloud = cloud
|
||||
|
||||
@ -945,6 +945,7 @@ class SystemJobOptions(BaseModel):
|
||||
('cleanup_jobs', _('Remove jobs older than a certain number of days')),
|
||||
('cleanup_activitystream', _('Remove activity stream entries older than a certain number of days')),
|
||||
('cleanup_deleted', _('Purge previously deleted items from the database')),
|
||||
('cleanup_facts', _('Purge and/or reduce the granularity of system tracking data')),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
|
||||
@ -14,7 +14,7 @@ class Socket(object):
|
||||
Intended to allow alteration of backend details in a single, consistent
|
||||
way throughout the Tower application.
|
||||
"""
|
||||
def __init__(self, bucket, rw, debug=0, logger=None):
|
||||
def __init__(self, bucket, rw, debug=0, logger=None, nowait=False):
|
||||
"""Instantiate a Socket object, which uses ZeroMQ to actually perform
|
||||
passing a message back and forth.
|
||||
|
||||
@ -42,6 +42,7 @@ class Socket(object):
|
||||
|
||||
self._debug = debug
|
||||
self._logger = logger
|
||||
self._nowait = nowait
|
||||
|
||||
def __enter__(self):
|
||||
self.connect()
|
||||
@ -92,7 +93,10 @@ class Socket(object):
|
||||
# Okay, create the connection.
|
||||
if self._context is None:
|
||||
self._context = zmq.Context()
|
||||
self._socket = self._context.socket(self._rw)
|
||||
self._socket = self._context.socket(self._rw)
|
||||
if self._nowait:
|
||||
self._socket.setsockopt(zmq.RCVTIMEO, 2000)
|
||||
self._socket.setsockopt(zmq.LINGER, 1000)
|
||||
if self._rw == zmq.REQ:
|
||||
self._socket.connect(port)
|
||||
else:
|
||||
@ -134,8 +138,8 @@ class Socket(object):
|
||||
break
|
||||
except Exception as ex:
|
||||
if self._logger:
|
||||
self._logger.info('Publish Exception: %r; retry=%d',
|
||||
ex, retry, exc_info=True)
|
||||
self._logger.error('Publish Exception: %r; retry=%d',
|
||||
ex, retry, exc_info=True)
|
||||
if retry >= 3:
|
||||
raise
|
||||
|
||||
|
||||
@ -230,10 +230,10 @@ class BaseTask(Task):
|
||||
'''
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), *args))
|
||||
|
||||
def build_private_data(self, instance, **kwargs):
|
||||
def build_private_data(self, job, **kwargs):
|
||||
'''
|
||||
Return any private data that needs to be written to a temporary file
|
||||
for this task.
|
||||
Return SSH private key data (only if stored in DB as ssh_key_data).
|
||||
Return structure is a dict of the form:
|
||||
'''
|
||||
|
||||
def build_private_data_dir(self, instance, **kwargs):
|
||||
@ -244,20 +244,23 @@ class BaseTask(Task):
|
||||
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
||||
return path
|
||||
|
||||
def build_private_data_file(self, instance, **kwargs):
|
||||
def build_private_data_files(self, instance, **kwargs):
|
||||
'''
|
||||
Create a temporary file containing the private data.
|
||||
Create a temporary files containing the private data.
|
||||
Returns a dictionary with keys from build_private_data
|
||||
(i.e. 'credential', 'cloud_credential') and values the file path.
|
||||
'''
|
||||
private_data = self.build_private_data(instance, **kwargs)
|
||||
private_data_files = {}
|
||||
if private_data is not None:
|
||||
handle, path = tempfile.mkstemp(dir=kwargs.get('private_data_dir', None))
|
||||
f = os.fdopen(handle, 'w')
|
||||
f.write(private_data)
|
||||
f.close()
|
||||
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
|
||||
return path
|
||||
else:
|
||||
return ''
|
||||
for name, data in private_data.iteritems():
|
||||
handle, path = tempfile.mkstemp(dir=kwargs.get('private_data_dir', None))
|
||||
f = os.fdopen(handle, 'w')
|
||||
f.write(data)
|
||||
f.close()
|
||||
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
|
||||
private_data_files[name] = path
|
||||
return private_data_files
|
||||
|
||||
def build_passwords(self, instance, **kwargs):
|
||||
'''
|
||||
@ -434,7 +437,8 @@ class BaseTask(Task):
|
||||
# Fetch ansible version once here to support version-dependent features.
|
||||
kwargs['ansible_version'] = get_ansible_version()
|
||||
kwargs['private_data_dir'] = self.build_private_data_dir(instance, **kwargs)
|
||||
kwargs['private_data_file'] = self.build_private_data_file(instance, **kwargs)
|
||||
# May have to serialize the value
|
||||
kwargs['private_data_files'] = self.build_private_data_files(instance, **kwargs)
|
||||
kwargs['passwords'] = self.build_passwords(instance, **kwargs)
|
||||
args = self.build_args(instance, **kwargs)
|
||||
safe_args = self.build_safe_args(instance, **kwargs)
|
||||
@ -505,25 +509,22 @@ class RunJob(BaseTask):
|
||||
|
||||
def build_private_data(self, job, **kwargs):
|
||||
'''
|
||||
Return SSH private key data needed for this job (only if stored in DB
|
||||
as ssh_key_data).
|
||||
Returns a dict of the form
|
||||
dict['credential'] = <credential_decrypted_ssh_key_data>
|
||||
dict['cloud_credential'] = <cloud_credential_decrypted_ssh_key_data>
|
||||
'''
|
||||
job_credentials = ['credential', 'cloud_credential']
|
||||
private_data = {}
|
||||
# If we were sent SSH credentials, decrypt them and send them
|
||||
# back (they will be written to a temporary file).
|
||||
credential = getattr(job, 'credential', None)
|
||||
if credential:
|
||||
return decrypt_field(credential, 'ssh_key_data') or None
|
||||
|
||||
# We might also have been sent a cloud credential. If so, send it.
|
||||
#
|
||||
# This sets up an either/or situation with credential and cloud
|
||||
# credential when it comes to SSH data. This should be fine, as if
|
||||
# you're running against cloud instances, you'll be using the cloud
|
||||
# credentials to do so. I assert that no situation currently exists
|
||||
# where we need both.
|
||||
cloud_credential = getattr(job, 'cloud_credential', None)
|
||||
if cloud_credential:
|
||||
return decrypt_field(cloud_credential, 'ssh_key_data') or None
|
||||
for cred_name in job_credentials:
|
||||
credential = getattr(job, cred_name, None)
|
||||
if credential:
|
||||
if credential.ssh_key_data not in (None, ''):
|
||||
private_data[cred_name] = decrypt_field(credential, 'ssh_key_data') or ''
|
||||
|
||||
return private_data
|
||||
|
||||
def build_passwords(self, job, **kwargs):
|
||||
'''
|
||||
@ -583,10 +584,10 @@ class RunJob(BaseTask):
|
||||
elif cloud_cred and cloud_cred.kind == 'gce':
|
||||
env['GCE_EMAIL'] = cloud_cred.username
|
||||
env['GCE_PROJECT'] = cloud_cred.project
|
||||
env['GCE_PEM_FILE_PATH'] = kwargs['private_data_file']
|
||||
env['GCE_PEM_FILE_PATH'] = kwargs.get('private_data_files', {}).get('cloud_credential', '')
|
||||
elif cloud_cred and cloud_cred.kind == 'azure':
|
||||
env['AZURE_SUBSCRIPTION_ID'] = cloud_cred.username
|
||||
env['AZURE_CERT_PATH'] = kwargs['private_data_file']
|
||||
env['AZURE_CERT_PATH'] = kwargs.get('private_data_files', {}).get('cloud_credential', '')
|
||||
elif cloud_cred and cloud_cred.kind == 'vmware':
|
||||
env['VMWARE_USER'] = cloud_cred.username
|
||||
env['VMWARE_PASSWORD'] = decrypt_field(cloud_cred, 'password')
|
||||
@ -729,7 +730,7 @@ class RunJob(BaseTask):
|
||||
'''
|
||||
If using an SSH key, return the path for use by ssh-agent.
|
||||
'''
|
||||
return kwargs.get('private_data_file', '')
|
||||
return kwargs.get('private_data_files', {}).get('credential', '')
|
||||
|
||||
def should_use_proot(self, instance, **kwargs):
|
||||
'''
|
||||
@ -760,12 +761,17 @@ class RunProjectUpdate(BaseTask):
|
||||
name = 'awx.main.tasks.run_project_update'
|
||||
model = ProjectUpdate
|
||||
|
||||
|
||||
def build_private_data(self, project_update, **kwargs):
|
||||
'''
|
||||
Return SSH private key data needed for this project update.
|
||||
'''
|
||||
private_data = {}
|
||||
if project_update.credential:
|
||||
return decrypt_field(project_update.credential, 'ssh_key_data') or None
|
||||
credential = project_update.credential
|
||||
if credential.ssh_key_data not in (None, ''):
|
||||
private_data['scm_credential'] = decrypt_field(project_update.credential, 'ssh_key_data')
|
||||
return private_data
|
||||
|
||||
def build_passwords(self, project_update, **kwargs):
|
||||
'''
|
||||
@ -916,7 +922,7 @@ class RunProjectUpdate(BaseTask):
|
||||
'''
|
||||
If using an SSH key, return the path for use by ssh-agent.
|
||||
'''
|
||||
return kwargs.get('private_data_file', '')
|
||||
return kwargs.get('private_data_files', {}).get('scm_credential', '')
|
||||
|
||||
class RunInventoryUpdate(BaseTask):
|
||||
|
||||
@ -930,7 +936,7 @@ class RunInventoryUpdate(BaseTask):
|
||||
# If this is Microsoft Azure or GCE, return the RSA key
|
||||
if inventory_update.source in ('azure', 'gce'):
|
||||
credential = inventory_update.credential
|
||||
return decrypt_field(credential, 'ssh_key_data')
|
||||
return dict(cloud_credential=decrypt_field(credential, 'ssh_key_data'))
|
||||
|
||||
if inventory_update.source == 'openstack':
|
||||
credential = inventory_update.credential
|
||||
@ -938,8 +944,9 @@ class RunInventoryUpdate(BaseTask):
|
||||
username=credential.username,
|
||||
password=decrypt_field(credential, "password"),
|
||||
project_name=credential.project)
|
||||
openstack_data = {"clouds": {"devstack": {"auth": openstack_auth}}}
|
||||
return yaml.safe_dump(openstack_data, default_flow_style=False, allow_unicode=True)
|
||||
private_state = str(inventory_update.source_vars_dict.get("private", "true"))
|
||||
openstack_data = {"clouds": {"devstack": {"private": private_state, "auth": openstack_auth}}}
|
||||
return dict(cloud_credential=yaml.safe_dump(openstack_data, default_flow_style=False, allow_unicode=True))
|
||||
|
||||
cp = ConfigParser.ConfigParser()
|
||||
# Build custom ec2.ini for ec2 inventory script to use.
|
||||
@ -993,7 +1000,7 @@ class RunInventoryUpdate(BaseTask):
|
||||
if cp.sections():
|
||||
f = cStringIO.StringIO()
|
||||
cp.write(f)
|
||||
return f.getvalue()
|
||||
return dict(cloud_credential=f.getvalue())
|
||||
|
||||
def build_passwords(self, inventory_update, **kwargs):
|
||||
"""Build a dictionary of authentication/credential information for
|
||||
@ -1038,31 +1045,32 @@ class RunInventoryUpdate(BaseTask):
|
||||
# `awx/plugins/inventory` directory; those files should be kept in
|
||||
# sync with those in Ansible core at all times.
|
||||
passwords = kwargs.get('passwords', {})
|
||||
cloud_credential = kwargs.get('private_data_files', {}).get('cloud_credential', '')
|
||||
if inventory_update.source == 'ec2':
|
||||
if passwords.get('source_username', '') and passwords.get('source_password', ''):
|
||||
env['AWS_ACCESS_KEY_ID'] = passwords['source_username']
|
||||
env['AWS_SECRET_ACCESS_KEY'] = passwords['source_password']
|
||||
env['EC2_INI_PATH'] = kwargs.get('private_data_file', '')
|
||||
env['EC2_INI_PATH'] = cloud_credential
|
||||
elif inventory_update.source == 'rax':
|
||||
env['RAX_CREDS_FILE'] = kwargs.get('private_data_file', '')
|
||||
env['RAX_CREDS_FILE'] = cloud_credential
|
||||
env['RAX_REGION'] = inventory_update.source_regions or 'all'
|
||||
# Set this environment variable so the vendored package won't
|
||||
# complain about not being able to determine its version number.
|
||||
env['PBR_VERSION'] = '0.5.21'
|
||||
elif inventory_update.source == 'vmware':
|
||||
env['VMWARE_INI'] = kwargs.get('private_data_file', '')
|
||||
env['VMWARE_INI'] = cloud_credential
|
||||
env['VMWARE_HOST'] = passwords.get('source_host', '')
|
||||
env['VMWARE_USER'] = passwords.get('source_username', '')
|
||||
env['VMWARE_PASSWORD'] = passwords.get('source_password', '')
|
||||
elif inventory_update.source == 'azure':
|
||||
env['AZURE_SUBSCRIPTION_ID'] = passwords.get('source_username', '')
|
||||
env['AZURE_CERT_PATH'] = kwargs['private_data_file']
|
||||
env['AZURE_CERT_PATH'] = cloud_credential
|
||||
elif inventory_update.source == 'gce':
|
||||
env['GCE_EMAIL'] = passwords.get('source_username', '')
|
||||
env['GCE_PROJECT'] = passwords.get('source_project', '')
|
||||
env['GCE_PEM_FILE_PATH'] = kwargs['private_data_file']
|
||||
env['GCE_PEM_FILE_PATH'] = cloud_credential
|
||||
elif inventory_update.source == 'openstack':
|
||||
env['OPENSTACK_CONFIG_FILE'] = kwargs.get('private_data_file', '')
|
||||
env['OPENSTACK_CONFIG_FILE'] = cloud_credential
|
||||
elif inventory_update.source == 'file':
|
||||
# FIXME: Parse source_env to dict, update env.
|
||||
pass
|
||||
@ -1163,7 +1171,6 @@ class RunInventoryUpdate(BaseTask):
|
||||
def get_idle_timeout(self):
|
||||
return getattr(settings, 'INVENTORY_UPDATE_IDLE_TIMEOUT', None)
|
||||
|
||||
|
||||
class RunAdHocCommand(BaseTask):
|
||||
'''
|
||||
Celery task to run an ad hoc command using ansible.
|
||||
@ -1180,8 +1187,10 @@ class RunAdHocCommand(BaseTask):
|
||||
# If we were sent SSH credentials, decrypt them and send them
|
||||
# back (they will be written to a temporary file).
|
||||
creds = ad_hoc_command.credential
|
||||
if creds:
|
||||
return decrypt_field(creds, 'ssh_key_data') or None
|
||||
private_data = {}
|
||||
if creds and creds.ssh_key_data not in (None, ''):
|
||||
private_data['ad_hoc_credential'] = decrypt_field(creds, 'ssh_key_data') or ''
|
||||
return private_data
|
||||
|
||||
def build_passwords(self, ad_hoc_command, **kwargs):
|
||||
'''
|
||||
@ -1321,7 +1330,7 @@ class RunAdHocCommand(BaseTask):
|
||||
'''
|
||||
If using an SSH key, return the path for use by ssh-agent.
|
||||
'''
|
||||
return kwargs.get('private_data_file', '')
|
||||
return kwargs.get('private_data_files', {}).get('ad_hoc_credential', '')
|
||||
|
||||
def should_use_proot(self, instance, **kwargs):
|
||||
'''
|
||||
@ -1345,10 +1354,15 @@ class RunSystemJob(BaseTask):
|
||||
args = ['awx-manage', system_job.job_type]
|
||||
try:
|
||||
json_vars = json.loads(system_job.extra_vars)
|
||||
if 'days' in json_vars:
|
||||
args.extend(['--days', str(json_vars['days'])])
|
||||
if 'days' in json_vars and system_job.job_type != 'cleanup_facts':
|
||||
args.extend(['--days', str(json_vars.get('days', 60))])
|
||||
if system_job.job_type == 'cleanup_jobs':
|
||||
args.extend(['--jobs', '--project-updates', '--inventory-updates', '--management-jobs'])
|
||||
if system_job.job_type == 'cleanup_facts':
|
||||
if 'older_than' in json_vars:
|
||||
args.extend(['--older_than', str(json_vars['older_than'])])
|
||||
if 'granularity' in json_vars:
|
||||
args.extend(['--granularity', str(json_vars['granularity'])])
|
||||
# Keeping this around in case we want to break this out
|
||||
# if 'jobs' in json_vars and json_vars['jobs']:
|
||||
# args.extend(['--jobs'])
|
||||
|
||||
@ -28,6 +28,12 @@ class CleanupFactsCommandFunctionalTest(BaseCommandMixin, BaseTest, MongoDBRequi
|
||||
result, stdout, stderr = self.run_command('cleanup_facts', granularity='1w',older_than='5d')
|
||||
self.assertEqual(stdout, 'Deleted 0 facts.\n')
|
||||
|
||||
def test_invoke_all_deleted(self):
|
||||
self.create_hosts_and_facts(datetime(year=2015, day=2, month=1, microsecond=0), 10, 20)
|
||||
|
||||
result, stdout, stderr = self.run_command('cleanup_facts', granularity='0d', older_than='0d')
|
||||
self.assertEqual(stdout, 'Deleted 200 facts.\n')
|
||||
|
||||
def test_invoke_params_required(self):
|
||||
result, stdout, stderr = self.run_command('cleanup_facts')
|
||||
self.assertIsInstance(result, CommandError)
|
||||
|
||||
@ -1898,3 +1898,19 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
||||
other_inv_src_opts = {'source': 'custom', 'source_script': script_data['id']}
|
||||
with self.current_user(self.super_django_user):
|
||||
self.put(other_inv_src, other_inv_src_opts, expect=400)
|
||||
|
||||
def test_update_from_openstack(self):
|
||||
api_url = getattr(settings, 'TEST_OPENSTACK_HOST', '')
|
||||
api_user = getattr(settings, 'TEST_OPENSTACK_USER', '')
|
||||
api_password = getattr(settings, 'TEST_OPENSTACK_PASSWORD', '')
|
||||
api_project = getattr(settings, 'TEST_OPENSTACK_PROJECT', '')
|
||||
if not all([api_url, api_user, api_password, api_project]):
|
||||
self.skipTest("No test openstack credentials defined")
|
||||
self.create_test_license_file()
|
||||
credential = Credential.objects.create(kind='openstack',
|
||||
host=api_url,
|
||||
username=api_user,
|
||||
password=api_password,
|
||||
project=api_project)
|
||||
inventory_source = self.update_inventory_source(self.group, source='openstack', credential=credential)
|
||||
self.check_inventory_source(inventory_source)
|
||||
|
||||
@ -482,19 +482,37 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
|
||||
# Invalid auth can't trigger the launch endpoint
|
||||
self.check_invalid_auth(launch_url, {}, methods=('post',))
|
||||
|
||||
# Implicit, attached credentials
|
||||
with self.current_user(self.user_sue):
|
||||
response = self.post(launch_url, {}, expect=202)
|
||||
j = Job.objects.get(pk=response['job'])
|
||||
self.assertTrue(j.status == 'new')
|
||||
|
||||
# Explicit, override credentials
|
||||
with self.current_user(self.user_sue):
|
||||
response = self.post(launch_url, {'credential': self.cred_doug.pk}, expect=202)
|
||||
j = Job.objects.get(pk=response['job'])
|
||||
self.assertTrue(j.status == 'new')
|
||||
self.assertEqual(j.credential.pk, self.cred_doug.pk)
|
||||
|
||||
# Can't launch a job template without a credential defined
|
||||
# Explicit, override credentials
|
||||
with self.current_user(self.user_sue):
|
||||
response = self.post(launch_url, {'credential_id': self.cred_doug.pk}, expect=202)
|
||||
j = Job.objects.get(pk=response['job'])
|
||||
self.assertTrue(j.status == 'new')
|
||||
self.assertEqual(j.credential.pk, self.cred_doug.pk)
|
||||
|
||||
# Can't launch a job template without a credential defined (or if we
|
||||
# pass an invalid/inactive credential value).
|
||||
with self.current_user(self.user_sue):
|
||||
response = self.post(no_launch_url, {}, expect=400)
|
||||
response = self.post(no_launch_url, {'credential': 0}, expect=400)
|
||||
response = self.post(no_launch_url, {'credential_id': 0}, expect=400)
|
||||
response = self.post(no_launch_url, {'credential': 'one'}, expect=400)
|
||||
response = self.post(no_launch_url, {'credential_id': 'one'}, expect=400)
|
||||
self.cred_doug.mark_inactive()
|
||||
response = self.post(no_launch_url, {'credential': self.cred_doug.pk}, expect=400)
|
||||
response = self.post(no_launch_url, {'credential_id': self.cred_doug.pk}, expect=400)
|
||||
|
||||
# Job Templates without projects can not be launched
|
||||
with self.current_user(self.user_sue):
|
||||
@ -503,9 +521,9 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
|
||||
jt = JobTemplate.objects.get(pk=response['id'])
|
||||
jt.project = None
|
||||
jt.save()
|
||||
launch_url = reverse('api:job_template_launch',
|
||||
args=(response['id'],))
|
||||
self.post(launch_url, {}, expect=400)
|
||||
launch_url2 = reverse('api:job_template_launch',
|
||||
args=(response['id'],))
|
||||
self.post(launch_url2, {}, expect=400)
|
||||
|
||||
# Job Templates without inventory can not be launched
|
||||
with self.current_user(self.user_sue):
|
||||
@ -514,9 +532,15 @@ class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
|
||||
jt = JobTemplate.objects.get(pk=response['id'])
|
||||
jt.inventory = None
|
||||
jt.save()
|
||||
launch_url = reverse('api:job_template_launch',
|
||||
args=(response['id'],))
|
||||
self.post(launch_url, {}, expect=400)
|
||||
launch_url3 = reverse('api:job_template_launch',
|
||||
args=(response['id'],))
|
||||
self.post(launch_url3, {}, expect=400)
|
||||
|
||||
# Job Templates with deleted credentials cannot be launched.
|
||||
self.cred_sue.mark_inactive()
|
||||
with self.current_user(self.user_sue):
|
||||
response = self.post(launch_url, {}, expect=400)
|
||||
|
||||
|
||||
class JobTest(BaseJobTestMixin, django.test.TestCase):
|
||||
|
||||
|
||||
@ -486,8 +486,11 @@ class ProjectsTest(BaseTransactionTest):
|
||||
# can add credentials to a user (if user or org admin or super user)
|
||||
self.post(other_creds, data=new_credentials, expect=401)
|
||||
self.post(other_creds, data=new_credentials, expect=401, auth=self.get_invalid_credentials())
|
||||
new_credentials['team'] = team.pk
|
||||
result = self.post(other_creds, data=new_credentials, expect=201, auth=self.get_super_credentials())
|
||||
cred_user = result['id']
|
||||
self.assertEqual(result['team'], None)
|
||||
del new_credentials['team']
|
||||
new_credentials['name'] = 'credential2'
|
||||
self.post(other_creds, data=new_credentials, expect=201, auth=self.get_normal_credentials())
|
||||
new_credentials['name'] = 'credential3'
|
||||
@ -497,9 +500,12 @@ class ProjectsTest(BaseTransactionTest):
|
||||
|
||||
# can add credentials to a team
|
||||
new_credentials['name'] = 'credential'
|
||||
new_credentials['user'] = other.pk
|
||||
self.post(team_creds, data=new_credentials, expect=401)
|
||||
self.post(team_creds, data=new_credentials, expect=401, auth=self.get_invalid_credentials())
|
||||
self.post(team_creds, data=new_credentials, expect=201, auth=self.get_super_credentials())
|
||||
result = self.post(team_creds, data=new_credentials, expect=201, auth=self.get_super_credentials())
|
||||
self.assertEqual(result['user'], None)
|
||||
del new_credentials['user']
|
||||
new_credentials['name'] = 'credential2'
|
||||
result = self.post(team_creds, data=new_credentials, expect=201, auth=self.get_normal_credentials())
|
||||
new_credentials['name'] = 'credential3'
|
||||
@ -611,6 +617,25 @@ class ProjectsTest(BaseTransactionTest):
|
||||
cred_put_t = self.put(edit_creds2, data=d_cred_team, expect=200, auth=self.get_normal_credentials())
|
||||
self.put(edit_creds2, data=d_cred_team, expect=403, auth=self.get_other_credentials())
|
||||
|
||||
# Reassign credential between team and user.
|
||||
with self.current_user(self.super_django_user):
|
||||
self.post(team_creds, data=dict(id=cred_user.pk), expect=204)
|
||||
response = self.get(edit_creds1)
|
||||
self.assertEqual(response['team'], team.pk)
|
||||
self.assertEqual(response['user'], None)
|
||||
self.post(other_creds, data=dict(id=cred_user.pk), expect=204)
|
||||
response = self.get(edit_creds1)
|
||||
self.assertEqual(response['team'], None)
|
||||
self.assertEqual(response['user'], other.pk)
|
||||
self.post(other_creds, data=dict(id=cred_team.pk), expect=204)
|
||||
response = self.get(edit_creds2)
|
||||
self.assertEqual(response['team'], None)
|
||||
self.assertEqual(response['user'], other.pk)
|
||||
self.post(team_creds, data=dict(id=cred_team.pk), expect=204)
|
||||
response = self.get(edit_creds2)
|
||||
self.assertEqual(response['team'], team.pk)
|
||||
self.assertEqual(response['user'], None)
|
||||
|
||||
cred_put_t['disassociate'] = 1
|
||||
team_url = reverse('api:team_credentials_list', args=(cred_put_t['team'],))
|
||||
self.post(team_url, data=cred_put_t, expect=204, auth=self.get_normal_credentials())
|
||||
|
||||
@ -24,6 +24,7 @@ from django.utils.encoding import smart_str
|
||||
# PyCrypto
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
logger = logging.getLogger('awx.main.utils')
|
||||
|
||||
__all__ = ['get_object_or_400', 'get_object_or_403', 'camelcase_to_underscore',
|
||||
'get_ansible_version', 'get_awx_version', 'update_scm_url',
|
||||
@ -380,10 +381,13 @@ def get_system_task_capacity():
|
||||
def emit_websocket_notification(endpoint, event, payload):
|
||||
from awx.main.socket import Socket
|
||||
|
||||
with Socket('websocket', 'w') as websocket:
|
||||
payload['event'] = event
|
||||
payload['endpoint'] = endpoint
|
||||
websocket.publish(payload)
|
||||
try:
|
||||
with Socket('websocket', 'w', nowait=True, logger=logger) as websocket:
|
||||
payload['event'] = event
|
||||
payload['endpoint'] = endpoint
|
||||
websocket.publish(payload)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
_inventory_updates = threading.local()
|
||||
|
||||
|
||||
@ -72,6 +72,16 @@ Author: Eric Johnson <erjohnso@google.com>
|
||||
Version: 0.0.1
|
||||
'''
|
||||
|
||||
__requires__ = ['pycrypto>=2.6']
|
||||
try:
|
||||
import pkg_resources
|
||||
except ImportError:
|
||||
# Use pkg_resources to find the correct versions of libraries and set
|
||||
# sys.path appropriately when there are multiversion installs. We don't
|
||||
# fail here as there is code that better expresses the errors where the
|
||||
# library is used.
|
||||
pass
|
||||
|
||||
USER_AGENT_PRODUCT="Ansible-gce_inventory_plugin"
|
||||
USER_AGENT_VERSION="v1"
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ class OpenStackInventory(object):
|
||||
self.openstack_config = os_client_config.config.OpenStackConfig(
|
||||
config_files)
|
||||
self.clouds = shade.openstack_clouds(self.openstack_config)
|
||||
self.refresh = refresh
|
||||
self.refresh = True
|
||||
|
||||
self.cache_max_age = self.openstack_config.get_cache_max_age()
|
||||
cache_path = self.openstack_config.get_cache_path()
|
||||
@ -101,9 +101,9 @@ class OpenStackInventory(object):
|
||||
continue
|
||||
|
||||
server_vars = meta['server_vars']
|
||||
hostvars[server.name][
|
||||
'ansible_ssh_host'] = server_vars['interface_ip']
|
||||
hostvars[server.name]['ansible_ssh_host'] = server_vars['interface_ip']
|
||||
hostvars[server.name]['openstack'] = server_vars
|
||||
hostvars[server.name]['id'] = server_vars['id']
|
||||
|
||||
for group in meta['groups']:
|
||||
groups[group].append(server.name)
|
||||
|
||||
@ -118,7 +118,7 @@ class AzureInventory(object):
|
||||
the Windows Azure API provides.
|
||||
"""
|
||||
if hostname not in self.host_metadata:
|
||||
return "No host found: %s" % hostname
|
||||
return "No host found: %s" % json.dumps(self.host_metadata)
|
||||
if jsonify:
|
||||
return json.dumps(self.host_metadata[hostname])
|
||||
return self.host_metadata[hostname]
|
||||
@ -220,12 +220,19 @@ class AzureInventory(object):
|
||||
def add_deployment(self, cloud_service, deployment):
|
||||
"""Adds a deployment to the inventory and index"""
|
||||
for role in deployment.role_instance_list.role_instances:
|
||||
for ie in role.instance_endpoints.instance_endpoints:
|
||||
if ie.name == 'SSH':
|
||||
self.add_instance(role.instance_name, deployment, ie.public_port, cloud_service)
|
||||
break
|
||||
try:
|
||||
# Default port 22 unless port found with name 'SSH'
|
||||
port = '22'
|
||||
for ie in role.instance_endpoints.instance_endpoints:
|
||||
if ie.name == 'SSH':
|
||||
port = ie.public_port
|
||||
break
|
||||
except AttributeError as e:
|
||||
pass
|
||||
finally:
|
||||
self.add_instance(role.instance_name, deployment, port, cloud_service, role.instance_status)
|
||||
|
||||
def add_instance(self, hostname, deployment, ssh_port, cloud_service):
|
||||
def add_instance(self, hostname, deployment, ssh_port, cloud_service, status):
|
||||
"""Adds an instance to the inventory and index"""
|
||||
|
||||
dest = urlparse(deployment.url).hostname
|
||||
@ -234,7 +241,9 @@ class AzureInventory(object):
|
||||
self.index[hostname] = deployment.name
|
||||
|
||||
self.host_metadata[hostname] = dict(ansible_ssh_host=dest,
|
||||
ansible_ssh_port=int(ssh_port))
|
||||
ansible_ssh_port=int(ssh_port),
|
||||
instance_status=status,
|
||||
private_id=deployment.private_id)
|
||||
|
||||
# List of all azure deployments
|
||||
self.push(self.inventory, "azure", hostname)
|
||||
|
||||
@ -513,15 +513,15 @@ AZURE_REGIONS_BLACKLIST = []
|
||||
|
||||
# Inventory variable name/value for determining whether a host is active
|
||||
# in Microsoft Azure.
|
||||
AZURE_ENABLED_VAR = 'status'
|
||||
AZURE_ENABLED_VALUE = 'created'
|
||||
AZURE_ENABLED_VAR = 'instance_status'
|
||||
AZURE_ENABLED_VALUE = 'ReadyRole'
|
||||
|
||||
# Filter for allowed group and host names when importing inventory from
|
||||
# Microsoft Azure.
|
||||
AZURE_GROUP_FILTER = r'^.+$'
|
||||
AZURE_HOST_FILTER = r'^.+$'
|
||||
AZURE_EXCLUDE_EMPTY_GROUPS = True
|
||||
AZURE_INSTANCE_ID_VAR = None
|
||||
AZURE_INSTANCE_ID_VAR = 'private_id'
|
||||
|
||||
# ---------------------
|
||||
# ----- OpenStack -----
|
||||
@ -531,7 +531,7 @@ OPENSTACK_ENABLED_VALUE = 'ACTIVE'
|
||||
OPENSTACK_GROUP_FILTER = r'^.+$'
|
||||
OPENSTACK_HOST_FILTER = r'^.+$'
|
||||
OPENSTACK_EXCLUDE_EMPTY_GROUPS = True
|
||||
OPENSTACK_INSTANCE_ID_VAR = None
|
||||
OPENSTACK_INSTANCE_ID_VAR = "id"
|
||||
|
||||
# ---------------------
|
||||
# -- Activity Stream --
|
||||
|
||||
@ -30,10 +30,7 @@
|
||||
// WebKit-style focus
|
||||
.tab-focus() {
|
||||
// Default
|
||||
outline: thin dotted;
|
||||
// WebKit
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
// Center-align a block level element
|
||||
|
||||
@ -36,6 +36,7 @@ export function AdhocCtrl($scope, $rootScope, $location, $routeParams,
|
||||
$scope.id = id;
|
||||
$scope.argsPopOver = "<p>These arguments are used with the" +
|
||||
" specified module.</p>";
|
||||
|
||||
// fix arguments help popover based on the module selected
|
||||
$scope.moduleChange = function () {
|
||||
// NOTE: for selenium testing link -
|
||||
@ -64,20 +65,13 @@ export function AdhocCtrl($scope, $rootScope, $location, $routeParams,
|
||||
$scope.providedHostPatterns = $scope.limit;
|
||||
delete $rootScope.hostPatterns;
|
||||
|
||||
if ($scope.removeLookUpInitialize) {
|
||||
$scope.removeLookUpInitialize();
|
||||
}
|
||||
$scope.removeLookUpInitialize = $scope.$on('lookUpInitialize', function () {
|
||||
LookUpInit({
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: (!Empty($scope.credential_id)) ? $scope.credential_id : null,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
input_type: 'radio'
|
||||
});
|
||||
|
||||
Wait('stop'); // END: form population
|
||||
LookUpInit({
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: (!Empty($scope.credential_id)) ? $scope.credential_id : null,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
input_type: 'radio'
|
||||
});
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
@ -87,7 +81,10 @@ export function AdhocCtrl($scope, $rootScope, $location, $routeParams,
|
||||
choicesReadyCount++;
|
||||
|
||||
if (choicesReadyCount === 2) {
|
||||
$scope.$emit('lookUpInitialize');
|
||||
// this sets the default options for the selects as specified by the controller.
|
||||
$scope.verbosity = $scope.adhoc_verbosity_options[$scope.verbosity_field.default];
|
||||
$("#forks-number").spinner("value", $scope.forks_field.default);
|
||||
Wait('stop'); // END: form population
|
||||
}
|
||||
});
|
||||
|
||||
@ -210,23 +207,6 @@ export function AdhocCtrl($scope, $rootScope, $location, $routeParams,
|
||||
credential: $scope.credential,
|
||||
callback: 'ContinueCred'
|
||||
});
|
||||
|
||||
// // Launch the adhoc job
|
||||
// Rest.setUrl(url);
|
||||
// Rest.post(data)
|
||||
// .success(function (data) {
|
||||
// Wait('stop');
|
||||
// $location.path("/ad_hoc_commands/" + data.id);
|
||||
// })
|
||||
// .error(function (data, status) {
|
||||
// ProcessErrors($scope, data, status, form, { hdr: 'Error!',
|
||||
// msg: 'Failed to launch adhoc command. POST returned status: ' +
|
||||
// status });
|
||||
// // TODO: still need to implement popping up a password prompt
|
||||
// // if the credential requires it. The way that the current end-
|
||||
// // point works is that I find out if I need to ask for a
|
||||
// // password from POST, thus I get an error response.
|
||||
// });
|
||||
};
|
||||
|
||||
// Remove all data input into the form
|
||||
@ -237,6 +217,8 @@ export function AdhocCtrl($scope, $rootScope, $location, $routeParams,
|
||||
}
|
||||
$scope.limit = $scope.providedHostPatterns;
|
||||
KindChange({ scope: $scope, form: form, reset: false });
|
||||
$scope.verbosity = $scope.adhoc_verbosity_options[$scope.verbosity_field.default];
|
||||
$("#forks-number").spinner("value", $scope.forks_field.default);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ export function Authenticate($log, $cookieStore, $compile, $window, $rootScope,
|
||||
"<div class=\"login-alert\" ng-show=\"sessionExpired\">Your session timed out due to inactivity. Please sign in.</div>\n" +
|
||||
"<form id=\"login-form\" name=\"loginForm\" class=\"form-horizontal\" autocomplete=\"off\" novalidate >\n" +
|
||||
"<div class=\"form-group\">\n" +
|
||||
"<label class=\"control-label col-md-offset-1 col-md-2 col-sm-offset-1 col-sm-2 col-xs-3 prepend-asterisk\">Username</label>\n" +
|
||||
"<label class=\"control-label col-md-offset-1 col-md-2 col-sm-offset-1 col-sm-2 col-xs-3 prepend-asterisk prepend-asterisk--login\">Username</label>\n" +
|
||||
"<div class=\"col-md-8 col-sm-8 col-xs-9\">\n" +
|
||||
"<input type=\"text\" name=\"login_username\" class=\"form-control\" ng-model=\"login_username\"" +
|
||||
"id=\"login-username\" autocomplete=\"off\" required>\n" +
|
||||
@ -125,7 +125,7 @@ export function Authenticate($log, $cookieStore, $compile, $window, $rootScope,
|
||||
"</div>\n" +
|
||||
"</div>\n" +
|
||||
"<div class=\"form-group\">\n" +
|
||||
"<label class=\"control-label col-md-offset-1 col-md-2 col-sm-offset-1 col-sm-2 col-xs-3 prepend-asterisk\">Password</label>\n" +
|
||||
"<label class=\"control-label col-md-offset-1 col-md-2 col-sm-offset-1 col-sm-2 col-xs-3 prepend-asterisk prepend-asterisk--login\">Password</label>\n" +
|
||||
"<div class=\"col-md-8 col-sm-8 col-xs-9\">\n" +
|
||||
"<input type=\"password\" name=\"login_password\" id=\"login-password\" class=\"form-control\"" +
|
||||
"ng-model=\"login_password\" required autocomplete=\"off\">\n" +
|
||||
|
||||
@ -249,7 +249,7 @@ JobTemplatesList.$inject = ['$scope', '$rootScope', '$location', '$log', '$route
|
||||
export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GetBasePath,
|
||||
InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange, Wait, Empty, ToJSON,
|
||||
CallbackHelpInit, SurveyControllerInit, Prompt) {
|
||||
CallbackHelpInit, SurveyControllerInit, Prompt, GetChoices) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
@ -274,18 +274,6 @@ export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $
|
||||
$scope.parseType = 'yaml';
|
||||
ParseTypeChange({ scope: $scope, field_id: 'job_templates_variables', onChange: callback });
|
||||
|
||||
$scope.job_type_options = [
|
||||
{ value: 'run', label: 'Run' },
|
||||
{ value: 'check', label: 'Check' },
|
||||
{ value: 'scan' , label: 'Scan'}
|
||||
];
|
||||
|
||||
$scope.verbosity_options = [
|
||||
{ value: 0, label: 'Default' },
|
||||
{ value: 1, label: 'Verbose' },
|
||||
{ value: 3, label: 'Debug' }
|
||||
];
|
||||
|
||||
$scope.playbook_options = [];
|
||||
$scope.allow_callbacks = 'false';
|
||||
|
||||
@ -315,34 +303,70 @@ export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $
|
||||
CloudCredentialList.name = 'cloudcredentials';
|
||||
CloudCredentialList.iterator = 'cloudcredential';
|
||||
|
||||
LookUpInit({
|
||||
url: GetBasePath('credentials') + '?cloud=true',
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: null,
|
||||
list: CloudCredentialList,
|
||||
field: 'cloud_credential',
|
||||
hdr: 'Select Cloud Credential',
|
||||
input_type: 'radio'
|
||||
});
|
||||
|
||||
LookUpInit({
|
||||
url: GetBasePath('credentials') + '?kind=ssh',
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: null,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
hdr: 'Select Machine Credential',
|
||||
input_type: "radio"
|
||||
});
|
||||
|
||||
SurveyControllerInit({
|
||||
scope: $scope,
|
||||
parent_scope: $scope
|
||||
});
|
||||
|
||||
if ($scope.removeLookUpInitialize) {
|
||||
$scope.removeLookUpInitialize();
|
||||
}
|
||||
$scope.removeLookUpInitialize = $scope.$on('lookUpInitialize', function () {
|
||||
LookUpInit({
|
||||
url: GetBasePath('credentials') + '?cloud=true',
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: null,
|
||||
list: CloudCredentialList,
|
||||
field: 'cloud_credential',
|
||||
hdr: 'Select Cloud Credential',
|
||||
input_type: 'radio'
|
||||
});
|
||||
|
||||
LookUpInit({
|
||||
url: GetBasePath('credentials') + '?kind=ssh',
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: null,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
hdr: 'Select Machine Credential',
|
||||
input_type: "radio"
|
||||
});
|
||||
});
|
||||
|
||||
var selectCount = 0;
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReadyVerbosity', function () {
|
||||
selectCount++;
|
||||
if (selectCount === 2) {
|
||||
// this sets the default options for the selects as specified by the controller.
|
||||
$scope.verbosity = $scope.verbosity_options[$scope.verbosity_field.default];
|
||||
$scope.job_type = $scope.job_type_options[$scope.job_type_field.default];
|
||||
$scope.$emit('lookUpInitialize');
|
||||
}
|
||||
});
|
||||
|
||||
// setup verbosity options select
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'verbosity',
|
||||
variable: 'verbosity_options',
|
||||
callback: 'choicesReadyVerbosity'
|
||||
});
|
||||
|
||||
// setup job type options select
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'job_type',
|
||||
variable: 'job_type_options',
|
||||
callback: 'choicesReadyVerbosity'
|
||||
});
|
||||
|
||||
// Update playbook select whenever project value changes
|
||||
selectPlaybook = function (oldValue, newValue) {
|
||||
@ -440,7 +464,7 @@ export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $
|
||||
break;
|
||||
}
|
||||
if (msg) {
|
||||
Alert('Waning', msg, 'alert-info');
|
||||
Alert('Warning', msg, 'alert-info');
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
@ -621,7 +645,7 @@ export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $
|
||||
JobTemplatesAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope',
|
||||
'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit',
|
||||
'md5Setup', 'ParseTypeChange', 'Wait', 'Empty', 'ToJSON', 'CallbackHelpInit', 'SurveyControllerInit', 'Prompt'
|
||||
'md5Setup', 'ParseTypeChange', 'Wait', 'Empty', 'ToJSON', 'CallbackHelpInit', 'SurveyControllerInit', 'Prompt', 'GetChoices'
|
||||
];
|
||||
|
||||
|
||||
@ -653,19 +677,6 @@ export function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log,
|
||||
$scope.parseType = 'yaml';
|
||||
$scope.showJobType = false;
|
||||
|
||||
// Our job type options
|
||||
$scope.job_type_options = [
|
||||
{ value: 'run', label: 'Run' },
|
||||
{ value: 'check', label: 'Check' },
|
||||
{ value: 'scan', label: 'Scan'}
|
||||
];
|
||||
|
||||
$scope.verbosity_options = [
|
||||
{ value: 0, label: 'Default' },
|
||||
{ value: 1, label: 'Verbose' },
|
||||
{ value: 3, label: 'Debug' }
|
||||
];
|
||||
|
||||
SurveyControllerInit({
|
||||
scope: $scope,
|
||||
parent_scope: $scope,
|
||||
@ -770,7 +781,7 @@ export function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log,
|
||||
}
|
||||
Wait('stop');
|
||||
if (msg) {
|
||||
Alert('Waning', msg, 'alert-info');
|
||||
Alert('Warning', msg, 'alert-info');
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
@ -963,7 +974,7 @@ export function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log,
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
choicesCount++;
|
||||
if (choicesCount === 2) {
|
||||
if (choicesCount === 4) {
|
||||
$scope.$emit('LoadJobs');
|
||||
}
|
||||
});
|
||||
@ -984,6 +995,24 @@ export function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log,
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
|
||||
// setup verbosity options lookup
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'verbosity',
|
||||
variable: 'verbosity_options',
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
|
||||
// setup job type options lookup
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'job_type',
|
||||
variable: 'job_type_options',
|
||||
callback: 'choicesReady'
|
||||
});
|
||||
|
||||
function saveCompleted() {
|
||||
setTimeout(function() {
|
||||
$scope.$apply(function() {
|
||||
|
||||
@ -104,6 +104,7 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $routePa
|
||||
scope: scheduled_scope,
|
||||
list: ScheduledJobsList,
|
||||
id: 'scheduled-jobs-tab',
|
||||
searchSize: 'col-lg-4 col-md-4 col-sm-4 col-xs-12',
|
||||
url: GetBasePath('schedules') + '?next_run__isnull=false',
|
||||
pageSize: max_rows
|
||||
});
|
||||
|
||||
@ -136,6 +136,7 @@ export function PermissionsAdd($scope, $rootScope, $compile, $location, $log, $r
|
||||
master.category = 'Inventory';
|
||||
master.inventoryrequired = true;
|
||||
master.projectrequired = false;
|
||||
$scope.run_ad_hoc_commands = false;
|
||||
|
||||
LookUpInit({
|
||||
scope: $scope,
|
||||
@ -155,6 +156,22 @@ export function PermissionsAdd($scope, $rootScope, $compile, $location, $log, $r
|
||||
input_type: 'radio'
|
||||
});
|
||||
|
||||
$scope.changeAdhocCommandCheckbox = function () {
|
||||
if ($scope.category === 'Deploy') {
|
||||
$scope.run_ad_hoc_command = false;
|
||||
} else {
|
||||
if ($scope.permission_type === 'admin') {
|
||||
$scope.run_ad_hoc_commands = true;
|
||||
$("#permission_run_ad_hoc_commands_chbox").attr("disabled", true);
|
||||
} else {
|
||||
if (!$scope.run_ad_hoc_commands) {
|
||||
$scope.run_ad_hoc_commands = false;
|
||||
}
|
||||
$("#permission_run_ad_hoc_commands_chbox").attr("disabled", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Save
|
||||
$scope.formSave = function () {
|
||||
var fld, url, data = {};
|
||||
@ -226,12 +243,25 @@ export function PermissionsEdit($scope, $rootScope, $compile, $location, $log, $
|
||||
defaultUrl = GetBasePath('base') + 'permissions/' + id + '/',
|
||||
master = {};
|
||||
|
||||
$scope.changeAdhocCommandCheckbox = function () {
|
||||
if ($scope.category === 'Deploy') {
|
||||
$scope.run_ad_hoc_command = false;
|
||||
} else {
|
||||
if ($scope.permission_type === 'admin') {
|
||||
$scope.run_ad_hoc_commands = true;
|
||||
$("#permission_run_ad_hoc_commands_chbox").attr("disabled", true);
|
||||
} else {
|
||||
if (!$scope.run_ad_hoc_commands) {
|
||||
$scope.run_ad_hoc_commands = false;
|
||||
}
|
||||
$("#permission_run_ad_hoc_commands_chbox").attr("disabled", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
||||
generator.reset();
|
||||
|
||||
|
||||
|
||||
|
||||
$scope.selectCategory = function (resetIn) {
|
||||
var reset = (resetIn === false) ? false : true;
|
||||
PermissionCategoryChange({ scope: $scope, reset: reset });
|
||||
@ -285,6 +315,8 @@ export function PermissionsEdit($scope, $rootScope, $compile, $location, $log, $
|
||||
input_type: 'radio'
|
||||
});
|
||||
|
||||
$scope.changeAdhocCommandCheckbox();
|
||||
|
||||
if (!$scope.PermissionAddAllowed) {
|
||||
// If not a privileged user, disable access
|
||||
$('form[name="permission_form"]').find('select, input, button').each(function () {
|
||||
|
||||
@ -48,11 +48,11 @@ function HostStatusGraph($compile, $window) {
|
||||
if(data.hosts.total+data.hosts.failed>0){
|
||||
data = [
|
||||
{ "label": "Successful",
|
||||
"color": "#00aa00",
|
||||
"color": "#60D66F",
|
||||
"value" : data.hosts.total
|
||||
} ,
|
||||
{ "label": "Failed",
|
||||
"color" : "#aa0000",
|
||||
"color" : "#ff5850",
|
||||
"value" : data.hosts.failed
|
||||
}
|
||||
];
|
||||
@ -68,7 +68,7 @@ function HostStatusGraph($compile, $window) {
|
||||
return '<b>'+x+'</b>'+ '<p>' + Math.floor(y.replace(',','')) + ' Hosts ' + '</p>';
|
||||
})
|
||||
.labelType("percent")
|
||||
.color(['#00aa00', '#aa0000']);
|
||||
.color(['#60D66F', '#ff5850']);
|
||||
|
||||
d3.select(element.find('svg')[0])
|
||||
.datum(data)
|
||||
|
||||
@ -46,12 +46,12 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG
|
||||
scope.jobType = jobtype;
|
||||
|
||||
var timeFormat, graphData = [
|
||||
{ "color": "#00aa00",
|
||||
{ "color": "#60D66F",
|
||||
"key": "Successful",
|
||||
"values": data.jobs.successful
|
||||
},
|
||||
{ "key" : "Failed" ,
|
||||
"color" : "#aa0000",
|
||||
"color" : "#ff5850",
|
||||
"values": data.jobs.failed
|
||||
}
|
||||
];
|
||||
|
||||
@ -82,14 +82,15 @@ export default
|
||||
}
|
||||
},
|
||||
become_enabled: {
|
||||
label: 'Enable Become for Credential',
|
||||
label: 'Enable Privilege Escalation',
|
||||
type: 'checkbox',
|
||||
editRequired: false
|
||||
// awPopOver: '<p>If checked, user will be become the user ' +
|
||||
// 'specified by the credential.</p>',
|
||||
// dataPlacement: 'right',
|
||||
// dataTitle: 'Enable Become for Credential',
|
||||
// dataContainer: 'body'
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
column: 2,
|
||||
awPopOver: "<p>If enabled, run this playbook as an administrator. This is the equivalent of passing the<code> --become</code> option to the <code> ansible</code> command. </p>",
|
||||
dataPlacement: 'right',
|
||||
dataTitle: 'Become Privilege Escalation',
|
||||
dataContainer: "body"
|
||||
},
|
||||
verbosity: {
|
||||
label: 'Verbosity',
|
||||
@ -103,8 +104,28 @@ export default
|
||||
'out of the command run that are supported.',
|
||||
dataTitle: 'Module',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body'
|
||||
}
|
||||
dataContainer: 'body',
|
||||
"default": 1
|
||||
},
|
||||
forks: {
|
||||
label: 'Forks',
|
||||
id: 'forks-number',
|
||||
type: 'number',
|
||||
integer: true,
|
||||
min: 0,
|
||||
spinner: true,
|
||||
"default": 0,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
'class': "input-small",
|
||||
column: 1,
|
||||
awPopOver: '<p>The number of parallel or simultaneous processes to use while executing the command. 0 signifies ' +
|
||||
'the default value from the <a id="ansible_forks_docs" href=\"http://docs.ansible.com/intro_configuration.html#the-ansible-configuration-file\" ' +
|
||||
' target=\"_blank\">ansible configuration file</a>.</p>',
|
||||
dataTitle: 'Forks',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
|
||||
buttons: {
|
||||
|
||||
@ -157,7 +157,7 @@ export default
|
||||
labelBind: 'hostLabel',
|
||||
type: 'text',
|
||||
ngShow: "kind.value == 'vmware' || kind.value == 'openstack'",
|
||||
awPopOverWatch: "projectPopOver",
|
||||
awPopOverWatch: "hostPopOver",
|
||||
awPopOver: "set in helpers/credentials",
|
||||
dataTitle: 'Host',
|
||||
dataPlacement: 'right',
|
||||
|
||||
@ -176,7 +176,7 @@ export default
|
||||
'class': "input-small",
|
||||
column: 1,
|
||||
awPopOver: '<p>The number of parallel or simultaneous processes to use while executing the playbook. 0 signifies ' +
|
||||
'the default value from the <a href=\"http://docs.ansible.com/intro_configuration.html#the-ansible-configuration-file\" ' +
|
||||
'the default value from the <a id="ansible_forks_docs" href=\"http://docs.ansible.com/intro_configuration.html#the-ansible-configuration-file\" ' +
|
||||
' target=\"_blank\">ansible configuration file</a>.</p>',
|
||||
dataTitle: 'Forks',
|
||||
dataPlacement: 'right',
|
||||
@ -199,7 +199,7 @@ export default
|
||||
label: 'Verbosity',
|
||||
type: 'select',
|
||||
ngOptions: 'v.label for v in verbosity_options track by v.value',
|
||||
"default": 0,
|
||||
"default": 1,
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
column: 1,
|
||||
|
||||
@ -97,6 +97,7 @@ export default
|
||||
labelClass: 'prepend-asterisk',
|
||||
type: 'radio_group',
|
||||
class: 'squeeze',
|
||||
ngChange: 'changeAdhocCommandCheckbox()',
|
||||
options: [{
|
||||
label: 'Read',
|
||||
value: 'read',
|
||||
|
||||
@ -53,11 +53,12 @@ export default
|
||||
},
|
||||
source_regions: {
|
||||
label: 'Regions',
|
||||
type: 'text',
|
||||
type: 'select',
|
||||
ngOptions: 'source.label for source in source_region_choices track by source.value',
|
||||
multiSelect: true,
|
||||
ngShow: "source && (source.value == 'rax' || source.value == 'ec2' || source.value == 'gce' || source.value == 'azure')",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awMultiselect: 'source_region_choices',
|
||||
dataTitle: 'Source Regions',
|
||||
dataPlacement: 'right',
|
||||
awPopOver: "<p>Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " +
|
||||
@ -87,11 +88,12 @@ export default
|
||||
},
|
||||
group_by: {
|
||||
label: 'Only Group By',
|
||||
type: 'text',
|
||||
type: 'select',
|
||||
ngShow: "source && source.value == 'ec2'",
|
||||
ngOptions: 'source.label for source in group_by_choices track by source.value',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awMultiselect: 'group_by_choices',
|
||||
multiSelect: true,
|
||||
dataTitle: 'Only Group By',
|
||||
dataPlacement: 'right',
|
||||
awPopOver: "<p>Select which groups to create automatically. " +
|
||||
@ -115,9 +117,10 @@ export default
|
||||
ngShow: "source && source.value === 'custom'",
|
||||
sourceModel: 'source_script',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpSource_script()' , //'lookUpCustom_inventory()',
|
||||
addRequired: true,
|
||||
editRequired: true
|
||||
ngClick: 'lookUpSource_script()' ,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
ngRequired: "source && source.value === 'custom'",
|
||||
},
|
||||
extra_vars: {
|
||||
label: 'Environment Variables', //"{{vars_label}}" ,
|
||||
@ -162,7 +165,9 @@ export default
|
||||
},
|
||||
inventory_variables: {
|
||||
label: 'Source Variables', //"{{vars_label}}" ,
|
||||
ngShow: "source && (source.value == 'vmware')",
|
||||
|
||||
ngShow: "source && (source.value == 'vmware' || " +
|
||||
"source.value == 'openstack')",
|
||||
type: 'textarea',
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
* Copyright (c) 2015 AnsibleWorks, Inc.
|
||||
*
|
||||
* GroupsHelper
|
||||
*
|
||||
@ -231,105 +231,118 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO: Document
|
||||
*
|
||||
*/
|
||||
.factory('SourceChange', ['GetBasePath', 'CredentialList', 'LookUpInit', 'Empty', 'Wait', 'ParseTypeChange', 'CustomInventoryList' ,
|
||||
function (GetBasePath, CredentialList, LookUpInit, Empty, Wait, ParseTypeChange, CustomInventoryList) {
|
||||
return function (params) {
|
||||
function (GetBasePath, CredentialList, LookUpInit, Empty, Wait, ParseTypeChange, CustomInventoryList) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
form = params.form,
|
||||
kind, url, callback, invUrl;
|
||||
var scope = params.scope,
|
||||
form = params.form,
|
||||
kind, url, callback, invUrl;
|
||||
|
||||
if (!Empty(scope.source)) {
|
||||
if (scope.source.value === 'file') {
|
||||
scope.sourcePathRequired = true;
|
||||
} else {
|
||||
scope.sourcePathRequired = false;
|
||||
// reset fields
|
||||
scope.source_path = '';
|
||||
scope[form.name + '_form'].source_path.$setValidity('required', true);
|
||||
}
|
||||
if (scope.source.value === 'rax') {
|
||||
scope.source_region_choices = scope.rax_regions;
|
||||
//$('#s2id_group_source_regions').select2('data', []);
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
} else if (scope.source.value === 'ec2') {
|
||||
scope.source_region_choices = scope.ec2_regions;
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
scope.group_by_choices = scope.ec2_group_by;
|
||||
$('#s2id_group_by').select2('data', []);
|
||||
$('#source_form').addClass('squeeze');
|
||||
} else if (scope.source.value === 'gce') {
|
||||
scope.source_region_choices = scope.gce_regions;
|
||||
//$('#s2id_group_source_regions').select2('data', []);
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
} else if (scope.source.value === 'azure') {
|
||||
scope.source_region_choices = scope.azure_regions;
|
||||
//$('#s2id_group_source_regions').select2('data', []);
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
}
|
||||
if(scope.source.value==="custom"){
|
||||
// need to filter the possible custom scripts by the organization defined for the current inventory
|
||||
invUrl = GetBasePath('inventory_scripts') + '?organization='+scope.$parent.inventory.organization;
|
||||
LookUpInit({
|
||||
url: invUrl,
|
||||
scope: scope,
|
||||
form: form,
|
||||
hdr: "Select Custom Inventory",
|
||||
list: CustomInventoryList,
|
||||
field: 'source_script',
|
||||
input_type: 'radio'
|
||||
});
|
||||
scope.extra_vars = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||
ParseTypeChange({ scope: scope, variable: 'extra_vars', parse_variable: form.fields.extra_vars.parseTypeName,
|
||||
field_id: 'source_extra_vars', onReady: callback });
|
||||
}
|
||||
if(scope.source.value==="vmware"){
|
||||
scope.inventory_variables = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||
ParseTypeChange({ scope: scope, variable: 'inventory_variables', parse_variable: form.fields.inventory_variables.parseTypeName,
|
||||
field_id: 'source_inventory_variables', onReady: callback });
|
||||
}
|
||||
if (scope.source.value === 'rax' || scope.source.value === 'ec2'|| scope.source.value==='gce' || scope.source.value === 'azure' || scope.source.value === 'vmware') {
|
||||
kind = (scope.source.value === 'rax') ? 'rax' : (scope.source.value==='gce') ? 'gce' : (scope.source.value==='azure') ? 'azure' : (scope.source.value === 'vmware') ? 'vmware' : 'aws' ;
|
||||
url = GetBasePath('credentials') + '?cloud=true&kind=' + kind;
|
||||
LookUpInit({
|
||||
url: url,
|
||||
scope: scope,
|
||||
form: form,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
input_type: "radio"
|
||||
});
|
||||
if ($('#group_tabs .active a').text() === 'Source' && (scope.source.value === 'ec2' )) {
|
||||
callback = function(){ Wait('stop'); };
|
||||
Wait('start');
|
||||
scope.source_vars = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||
ParseTypeChange({ scope: scope, variable: 'source_vars', parse_variable: form.fields.source_vars.parseTypeName,
|
||||
field_id: 'source_source_vars', onReady: callback });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
if (!Empty(scope.source)) {
|
||||
if (scope.source.value === 'file') {
|
||||
scope.sourcePathRequired = true;
|
||||
} else {
|
||||
scope.sourcePathRequired = false;
|
||||
// reset fields
|
||||
scope.source_path = '';
|
||||
scope[form.name + '_form'].source_path.$setValidity('required', true);
|
||||
}
|
||||
if (scope.source.value === 'rax') {
|
||||
scope.source_region_choices = scope.rax_regions;
|
||||
//$('#s2id_group_source_regions').select2('data', []);
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
} else if (scope.source.value === 'ec2') {
|
||||
scope.source_region_choices = scope.ec2_regions;
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
scope.group_by_choices = scope.ec2_group_by;
|
||||
$('#s2id_group_by').select2('data', []);
|
||||
$('#source_form').addClass('squeeze');
|
||||
} else if (scope.source.value === 'gce') {
|
||||
scope.source_region_choices = scope.gce_regions;
|
||||
//$('#s2id_group_source_regions').select2('data', []);
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
} else if (scope.source.value === 'azure') {
|
||||
scope.source_region_choices = scope.azure_regions;
|
||||
//$('#s2id_group_source_regions').select2('data', []);
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
}
|
||||
if(scope.source.value==="custom"){
|
||||
// need to filter the possible custom scripts by the organization defined for the current inventory
|
||||
invUrl = GetBasePath('inventory_scripts') + '?organization='+scope.$parent.inventory.organization;
|
||||
LookUpInit({
|
||||
url: invUrl,
|
||||
scope: scope,
|
||||
form: form,
|
||||
hdr: "Select Custom Inventory",
|
||||
list: CustomInventoryList,
|
||||
field: 'source_script',
|
||||
input_type: 'radio'
|
||||
});
|
||||
scope.extra_vars = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||
ParseTypeChange({ scope: scope, variable: 'extra_vars', parse_variable: form.fields.extra_vars.parseTypeName,
|
||||
field_id: 'source_extra_vars', onReady: callback });
|
||||
}
|
||||
if(scope.source.value==="vmware" ||
|
||||
scope.source.value==="openstack"){
|
||||
scope.inventory_variables = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||
ParseTypeChange({ scope: scope, variable: 'inventory_variables', parse_variable: form.fields.inventory_variables.parseTypeName,
|
||||
field_id: 'source_inventory_variables', onReady: callback });
|
||||
}
|
||||
if (scope.source.value === 'rax' ||
|
||||
scope.source.value === 'ec2' ||
|
||||
scope.source.value==='gce' ||
|
||||
scope.source.value === 'azure' ||
|
||||
scope.source.value === 'vmware' ||
|
||||
scope.source.value === 'openstack') {
|
||||
if (scope.source.value === 'ec2') {
|
||||
kind = 'aws';
|
||||
} else {
|
||||
kind = scope.source.value;
|
||||
}
|
||||
url = GetBasePath('credentials') + '?cloud=true&kind=' + kind;
|
||||
LookUpInit({
|
||||
url: url,
|
||||
scope: scope,
|
||||
form: form,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
input_type: "radio"
|
||||
});
|
||||
if ($('#group_tabs .active a').text() === 'Source' &&
|
||||
(scope.source.value === 'ec2' )) {
|
||||
callback = function(){ Wait('stop'); };
|
||||
Wait('start');
|
||||
scope.source_vars = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||
ParseTypeChange({ scope: scope, variable: 'source_vars',
|
||||
parse_variable: form.fields.source_vars.parseTypeName,
|
||||
field_id: 'source_source_vars', onReady: callback });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
/**
|
||||
@ -700,11 +713,11 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
.factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', '$compile', 'Rest', 'Alert', 'GroupForm', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate',
|
||||
'LookUpInit', 'Empty', 'Wait', 'GetChoices', 'UpdateGroup', 'SourceChange', 'Find', 'WatchInventoryWindowResize',
|
||||
'ParseVariableString', 'ToJSON', 'GroupsScheduleListInit', 'SourceForm', 'SetSchedulesInnerDialogSize',
|
||||
'ParseVariableString', 'ToJSON', 'GroupsScheduleListInit', 'SourceForm', 'SetSchedulesInnerDialogSize', 'CreateSelect2',
|
||||
function ($rootScope, $location, $log, $routeParams, $compile, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors,
|
||||
GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, LookUpInit, Empty, Wait,
|
||||
GetChoices, UpdateGroup, SourceChange, Find, WatchInventoryWindowResize, ParseVariableString, ToJSON, GroupsScheduleListInit,
|
||||
SourceForm, SetSchedulesInnerDialogSize) {
|
||||
SourceForm, SetSchedulesInnerDialogSize, CreateSelect2) {
|
||||
return function (params) {
|
||||
|
||||
var parent_scope = params.scope,
|
||||
@ -905,7 +918,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
Wait('start');
|
||||
ParseTypeChange({ scope: sources_scope, variable: 'source_vars', parse_variable: SourceForm.fields.source_vars.parseTypeName,
|
||||
field_id: 'source_source_vars', onReady: waitStop });
|
||||
} else if (sources_scope.source && (sources_scope.source.value === 'vmware')) {
|
||||
} else if (sources_scope.source && (sources_scope.source.value === 'vmware' ||
|
||||
sources_scope.source.value === 'openstack')) {
|
||||
Wait('start');
|
||||
ParseTypeChange({ scope: sources_scope, variable: 'inventory_variables', parse_variable: SourceForm.fields.inventory_variables.parseTypeName,
|
||||
field_id: 'source_inventory_variables', onReady: waitStop });
|
||||
@ -1048,7 +1062,11 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
}
|
||||
}
|
||||
master.source_regions = opts;
|
||||
$('#s2id_source_source_regions').select2('data', opts);
|
||||
CreateSelect2({
|
||||
element: "#source_source_regions",
|
||||
opts: opts
|
||||
});
|
||||
|
||||
}
|
||||
} else {
|
||||
// If empty, default to all
|
||||
@ -1056,7 +1074,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
}];
|
||||
$('#s2id_source_source_regions').select2('data', master.source_regions);
|
||||
}
|
||||
if (data.group_by && data.source === 'ec2') {
|
||||
set = sources_scope.ec2_group_by;
|
||||
@ -1073,7 +1090,10 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
}
|
||||
}
|
||||
master.group_by = opts;
|
||||
$('#s2id_source_group_by').select2('data', opts);
|
||||
CreateSelect2({
|
||||
element: "#source_group_by",
|
||||
opts: opts
|
||||
});
|
||||
}
|
||||
sources_scope.group_update_url = data.related.update;
|
||||
modal_scope.$emit('groupVariablesLoaded'); // JT-- "groupVariablesLoaded" is where the schedule info is loaded, so I make a call after the sources_scope.source has been loaded
|
||||
@ -1249,17 +1269,19 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
};
|
||||
|
||||
// Create a string out of selected list of regions
|
||||
regions = $('#s2id_source_source_regions').select2("data");
|
||||
r = [];
|
||||
for (i = 0; i < regions.length; i++) {
|
||||
r.push(regions[i].id);
|
||||
if(sources_scope.source_regions){
|
||||
regions = $('#source_source_regions').select2("data");
|
||||
r = [];
|
||||
for (i = 0; i < regions.length; i++) {
|
||||
r.push(regions[i].id);
|
||||
}
|
||||
data.source_regions = r.join();
|
||||
}
|
||||
data.source_regions = r.join();
|
||||
|
||||
if (sources_scope.source && (sources_scope.source.value === 'ec2')) {
|
||||
data.instance_filters = sources_scope.instance_filters;
|
||||
// Create a string out of selected list of regions
|
||||
group_by = $('#s2id_source_group_by').select2("data");
|
||||
group_by = $('#source_group_by').select2("data");
|
||||
r = [];
|
||||
for (i = 0; i < group_by.length; i++) {
|
||||
r.push(group_by[i].id);
|
||||
@ -1276,7 +1298,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
data.source_vars = ToJSON(sources_scope.envParseType, sources_scope.extra_vars, true);
|
||||
}
|
||||
|
||||
if (sources_scope.source && (sources_scope.source.value === 'vmware')) {
|
||||
if (sources_scope.source && (sources_scope.source.value === 'vmware' ||
|
||||
sources_scope.source.value === 'openstack')) {
|
||||
data.source_vars = ToJSON(sources_scope.envParseType, sources_scope.inventory_variables, true);
|
||||
}
|
||||
|
||||
@ -1376,7 +1399,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
group_created = true;
|
||||
group_id = data.id;
|
||||
sources_scope.source_url = data.related.inventory_source;
|
||||
if (properties_scope.variables) {
|
||||
if (properties_scope.variables && properties_scope.variables !== "---") {
|
||||
modal_scope.$emit('updateVariables', json_data, data.related.variable_data);
|
||||
}
|
||||
else {
|
||||
|
||||
@ -1146,7 +1146,7 @@ export default
|
||||
graph_data.push({
|
||||
label: 'OK',
|
||||
value: (scope.host_summary.ok === scope.host_summary.total) ? 1 : scope.host_summary.ok,
|
||||
color: '#00aa00'
|
||||
color: '#60D66F'
|
||||
});
|
||||
}
|
||||
if (scope.host_summary.changed) {
|
||||
@ -1167,7 +1167,7 @@ export default
|
||||
graph_data.push({
|
||||
label: 'Failed',
|
||||
value: (scope.host_summary.failed === scope.host_summary.total) ? 1 : scope.host_summary.failed,
|
||||
color: '#aa0000'
|
||||
color: '#ff5850'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -710,9 +710,8 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm,
|
||||
if(data.vault_password === "ASK"){
|
||||
passwords.push("vault_password");
|
||||
}
|
||||
scope.$emit(callback, passwords);
|
||||
}
|
||||
|
||||
scope.$emit(callback, passwords);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
|
||||
@ -27,8 +27,8 @@ import listGenerator from 'tower/shared/list-generator/main';
|
||||
export default
|
||||
angular.module('LookUpHelper', ['RestServices', 'Utilities', 'SearchHelper', 'PaginationHelpers', listGenerator.name, 'ApiLoader', 'ModalDialog'])
|
||||
|
||||
.factory('LookUpInit', ['Alert', 'Rest', 'generateList', 'SearchInit', 'PaginateInit', 'GetBasePath', 'FormatDate', 'Empty', 'CreateDialog',
|
||||
function (Alert, Rest, GenerateList, SearchInit, PaginateInit, GetBasePath, FormatDate, Empty, CreateDialog) {
|
||||
.factory('LookUpInit', ['Alert', 'Rest', 'ProcessErrors', 'generateList', 'SearchInit', 'PaginateInit', 'GetBasePath', 'FormatDate', 'Empty', 'CreateDialog',
|
||||
function (Alert, Rest, ProcessErrors, GenerateList, SearchInit, PaginateInit, GetBasePath, FormatDate, Empty, CreateDialog) {
|
||||
return function (params) {
|
||||
|
||||
var parent_scope = params.scope,
|
||||
@ -63,6 +63,31 @@ export default
|
||||
$('input[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').attr('data-url', watchUrl);
|
||||
$('input[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').attr('data-source', field);
|
||||
|
||||
// Auto populate the field if there is only one result
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
if (data.count === 1) {
|
||||
parent_scope[field] = data.results[0].id;
|
||||
if (parent_scope[form.name + '_form'] && form.fields[field] && form.fields[field].sourceModel) {
|
||||
parent_scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] =
|
||||
data.results[0][form.fields[field].sourceField];
|
||||
if (parent_scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField]) {
|
||||
parent_scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField]
|
||||
.$setValidity('awlookup', true);
|
||||
}
|
||||
}
|
||||
if (parent_scope[form.name + '_form']) {
|
||||
parent_scope[form.name + '_form'].$setDirty();
|
||||
}
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(parent_scope, data, status, form, { hdr: 'Error!',
|
||||
msg: 'Failed to launch adhoc command. POST returned status: ' +
|
||||
status });
|
||||
});
|
||||
|
||||
|
||||
parent_scope['lookUp' + name] = function () {
|
||||
|
||||
|
||||
@ -570,6 +570,7 @@ export default
|
||||
list = params.list,
|
||||
id = params.id,
|
||||
url = params.url,
|
||||
searchSize = params.searchSize,
|
||||
pageSize = params.pageSize || 5,
|
||||
spinner = (params.spinner === undefined) ? true : params.spinner;
|
||||
|
||||
@ -579,7 +580,7 @@ export default
|
||||
id: id,
|
||||
breadCrumbs: false,
|
||||
scope: scope,
|
||||
searchSize: 'col-lg-6 col-md-6 col-sm-6 col-xs-12',
|
||||
searchSize: (searchSize) ? searchSize : 'col-lg-6 col-md-6 col-sm-6 col-xs-12',
|
||||
showSearch: true
|
||||
});
|
||||
|
||||
|
||||
@ -78,6 +78,9 @@ export default
|
||||
},{
|
||||
name: "Microsoft Azure",
|
||||
value: "azure"
|
||||
},{
|
||||
name: "Openstack",
|
||||
value: "openstack"
|
||||
}],
|
||||
sourceModel: 'inventory_source',
|
||||
sourceField: 'source',
|
||||
@ -86,7 +89,7 @@ export default
|
||||
has_external_source: {
|
||||
label: 'Has external source?',
|
||||
searchType: 'in',
|
||||
searchValue: 'ec2,rax,vmware,azure,gce',
|
||||
searchValue: 'ec2,rax,vmware,azure,gce,openstack',
|
||||
searchOnly: true,
|
||||
sourceModel: 'inventory_source',
|
||||
sourceField: 'source'
|
||||
@ -170,4 +173,4 @@ export default
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@ -47,6 +47,9 @@ export default
|
||||
},{
|
||||
name: "Microsoft Azure",
|
||||
value: "azure"
|
||||
},{
|
||||
name: "Openstack",
|
||||
value: "openstack"
|
||||
}],
|
||||
sourceModel: 'inventory_source',
|
||||
sourceField: 'source',
|
||||
@ -55,7 +58,7 @@ export default
|
||||
has_external_source: {
|
||||
label: 'Has external source?',
|
||||
searchType: 'in',
|
||||
searchValue: 'ec2,rax,vmware,azure,gce',
|
||||
searchValue: 'ec2,rax,vmware,azure,gce,openstack',
|
||||
searchOnly: true,
|
||||
sourceModel: 'inventory_source',
|
||||
sourceField: 'source'
|
||||
|
||||
@ -659,6 +659,75 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
|
||||
}
|
||||
])
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name shared.function:Utilities#CreateSelect2
|
||||
* @methodOf shared.function:Utilities
|
||||
* @description Make a regular select drop down a select2 dropdown
|
||||
* To make a ``<select>`` field a select2 select 2, create the field in the
|
||||
* form definition with the multiSelect flag set to true. In the controller
|
||||
* of the page in question, call the CreateSelect2 factory with the element
|
||||
* id (be sure to include the appropriate jquery identifier in the parameter)
|
||||
* or any options that should be pre-selected in the select2 field.
|
||||
* The array of options should be formatted as
|
||||
* ```
|
||||
* [
|
||||
* {
|
||||
* id: 'id' ,
|
||||
* text: 'text'
|
||||
* },
|
||||
* {
|
||||
* id: 'id' ,
|
||||
* text: 'text'
|
||||
* }
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
.factory('CreateSelect2', [
|
||||
function () {
|
||||
return function (params) {
|
||||
|
||||
var element = params.element,
|
||||
options = params.opts;
|
||||
|
||||
$.fn.select2.amd.require([
|
||||
"select2/utils",
|
||||
"select2/dropdown",
|
||||
"select2/dropdown/attachContainer",
|
||||
"select2/dropdown/search",
|
||||
], function (Utils, DropdownAdapter, AttachContainer, DropdownSearch) {
|
||||
|
||||
var CustomAdapter = Utils.Decorate(
|
||||
Utils.Decorate(
|
||||
DropdownAdapter,
|
||||
DropdownSearch
|
||||
),
|
||||
AttachContainer
|
||||
);
|
||||
|
||||
$(element).select2({
|
||||
dropdownAdapter: CustomAdapter,
|
||||
multiple: 'true',
|
||||
theme: "bootstrap",
|
||||
width: '100%'
|
||||
});
|
||||
if(options){
|
||||
for (var d = 0; d < $(element + " option").length; d++) {
|
||||
var item = $(element + " option")[d];
|
||||
for ( var f = 0; f < options.length; f++){
|
||||
if(item.value === options[f].id){
|
||||
// Append it to the select
|
||||
item.setAttribute('selected', 'selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(element).trigger('change');
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
}])
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name shared.function:Utilities#GetChoices
|
||||
|
||||
@ -620,33 +620,6 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
|
||||
};
|
||||
}])
|
||||
|
||||
.directive('awMultiSelect', [ function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm) {
|
||||
$(elm).multiselect ({
|
||||
buttonClass: 'btn-default, btn-mini',
|
||||
buttonWidth: 'auto',
|
||||
buttonContainer: '<div class="btn-group" />',
|
||||
maxHeight: false,
|
||||
buttonText: function(options) {
|
||||
if (options.length === 0) {
|
||||
return 'None selected <b class="caret"></b>';
|
||||
}
|
||||
if (options.length > 3) {
|
||||
return options.length + ' selected <b class="caret"></b>';
|
||||
}
|
||||
var selected = '';
|
||||
options.each(function() {
|
||||
selected += $(this).text() + ', ';
|
||||
});
|
||||
return selected.substr(0, selected.length -2) + ' <b class="caret"></b>';
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
//
|
||||
// Enable jqueryui spinner widget on a numeric input field
|
||||
//
|
||||
@ -728,43 +701,6 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
|
||||
};
|
||||
}])
|
||||
|
||||
|
||||
/*
|
||||
awMultiSelect
|
||||
Relies on select2.js to create a multi-select with tags.
|
||||
*/
|
||||
.directive('awMultiselect', [ function() {
|
||||
return {
|
||||
require: '^form', //inject the form into the ctrl parameter
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
$(elm).select2({
|
||||
multiple: true,
|
||||
data: function() {
|
||||
// dynamically load the possible values
|
||||
if (scope[attrs.awMultiselect]) {
|
||||
var set = scope[attrs.awMultiselect],
|
||||
opts = [], i;
|
||||
for (i=0; i < set.length; i++) {
|
||||
opts.push({ id: set[i].value, text: set[i].label });
|
||||
}
|
||||
return {results: opts };
|
||||
}
|
||||
return {results: { id: '', text: ''} };
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure the form buttons enable when the value changes
|
||||
$(elm).on('change', function() {
|
||||
ctrl.$setDirty();
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
|
||||
/*
|
||||
* Make an element draggable. Used on inventory groups tree.
|
||||
*
|
||||
|
||||
@ -671,10 +671,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
html += Attr(field, 'type');
|
||||
html += "ng-model=\"" + fld + '" ';
|
||||
html += "name=\"" + fld + '" ';
|
||||
if (form.name === "permission") {
|
||||
html += "ng-disabled='permission_type === \"admin\"'";
|
||||
html += "ng-checked='permission_type === \"admin\"'";
|
||||
}
|
||||
html += (field.ngChange) ? Attr(field, 'ngChange') : "";
|
||||
html += "id=\"" + form.name + "_" + fld + "_chbox\" ";
|
||||
html += (idx !== undefined) ? "_" + idx : "";
|
||||
@ -791,7 +787,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
field.awRequiredWhen.variable + "\" " : "";
|
||||
html += (field.awValidUrl) ? "aw-valid-url " : "";
|
||||
html += (field.associated && this.form.fields[field.associated].ask) ? "ng-disabled=\"" + field.associated + "_ask\" " : "";
|
||||
html += (field.awMultiselect) ? "aw-multiselect=\"" + field.awMultiselect + "\" " : "";
|
||||
html += ">\n";
|
||||
}
|
||||
|
||||
@ -915,7 +910,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
field.awRequiredWhen.variable + "' " : "";
|
||||
html += (field.awValidUrl) ? "aw-valid-url " : "";
|
||||
html += (field.associated && this.form.fields[field.associated].ask) ? "ng-disabled='" + field.associated + "_ask' " : "";
|
||||
html += (field.awMultiselect) ? "aw-multiselect='" + field.awMultiselect + "' " : "";
|
||||
html += ">\n";
|
||||
}
|
||||
|
||||
@ -1038,7 +1032,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
html += "class=\"form-control";
|
||||
html += (field['class']) ? " " + field['class'] : "";
|
||||
html += "\" ";
|
||||
html += this.attr(field, 'ngOptions');
|
||||
html += (field.ngOptions) ? this.attr(field, 'ngOptions') : "" ;
|
||||
html += (field.ngChange) ? this.attr(field, 'ngChange') : "";
|
||||
html += (field.ngDisabled) ? this.attr(field, 'ngDisabled'): "";
|
||||
html += (field.ngRequired) ? this.attr(field, 'ngRequired') : "";
|
||||
|
||||
@ -34,7 +34,7 @@ angular.module('PromptDialog', ['Utilities'])
|
||||
|
||||
var dialog = angular.element(document.getElementById('prompt-modal')),
|
||||
scope = dialog.scope(), cls, local_backdrop;
|
||||
|
||||
|
||||
scope.promptHeader = params.hdr;
|
||||
scope.promptBody = $sce.trustAsHtml(params.body);
|
||||
scope.promptAction = params.action;
|
||||
|
||||
@ -23,8 +23,8 @@ export default [ function() {
|
||||
barWidth: 7,
|
||||
barSpacing: 2,
|
||||
zeroBarColor: 'grey',
|
||||
posBarColor: '#00aa00',
|
||||
negBarColor: '#aa0000',
|
||||
posBarColor: '#60D66F',
|
||||
negBarColor: '#ff5850',
|
||||
tooltipFormatter: scope.formatter,
|
||||
tooltipFormat: '{{value:jobs}}',
|
||||
tooltipValueLookups: {
|
||||
|
||||
@ -45,13 +45,13 @@ angular.module('DashboardCountsWidget', ['RestServices', 'Utilities'])
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
if(dashboard.hosts.failed>0 ){
|
||||
$('#failed-hosts').replaceWith("<a style=\"color:#aa0000\" href=\"/#/home/hosts/?has_active_failures=true\" id=\"failed-hosts\">"+dashboard.hosts.failed+"</a>");
|
||||
$('#failed-hosts').replaceWith("<a style=\"color: #ff5850\" href=\"/#/home/hosts/?has_active_failures=true\" id=\"failed-hosts\">"+dashboard.hosts.failed+"</a>");
|
||||
}
|
||||
if(dashboard.inventories.inventory_failed>0 ){
|
||||
$('#failed-inventories').replaceWith("<a style=\"color:#aa0000\" href=/#/inventories/?inventory_sources_with_failures id=\"failed-inventories\">"+dashboard.inventories.inventory_failed+"</a>");
|
||||
$('#failed-inventories').replaceWith("<a style=\"color: #ff5850\" href=/#/inventories/?inventory_sources_with_failures id=\"failed-inventories\">"+dashboard.inventories.inventory_failed+"</a>");
|
||||
}
|
||||
if(dashboard.projects.failed>0 ){
|
||||
$('#failed-projects').replaceWith("<a style=\"color:#aa0000\" href=\"/#/projects/?status=failed\" id=\"failed-projects\">"+dashboard.projects.failed+"</a>");
|
||||
$('#failed-projects').replaceWith("<a style=\"color: #ff5850\" href=\"/#/projects/?status=failed\" id=\"failed-projects\">"+dashboard.projects.failed+"</a>");
|
||||
}
|
||||
scope.$emit('WidgetLoaded');
|
||||
|
||||
|
||||
@ -63,12 +63,12 @@ angular.module('HostPieChartWidget', ['RestServices', 'Utilities'])
|
||||
data = [
|
||||
{
|
||||
"label": "Successful",
|
||||
"color": "#00aa00",
|
||||
"color": "#60D66F",
|
||||
"value" : dashboard.hosts.total
|
||||
} ,
|
||||
{
|
||||
"label": "Failed",
|
||||
"color" : "#aa0000",
|
||||
"color" : "#ff5850",
|
||||
"value" : dashboard.hosts.failed
|
||||
}
|
||||
];
|
||||
@ -85,7 +85,7 @@ angular.module('HostPieChartWidget', ['RestServices', 'Utilities'])
|
||||
.tooltipContent(function(x, y) {
|
||||
return '<b>'+x+'</b>'+ '<p>' + Math.floor(y.replace(',','')) + ' Hosts ' + '</p>';
|
||||
})
|
||||
.color(['#00aa00', '#aa0000']);
|
||||
.color(['#60D66F', '#ff5850']);
|
||||
|
||||
host_pie_chart.pie.pieLabelsOutside(true).labelType("percent");
|
||||
|
||||
|
||||
@ -117,13 +117,13 @@ angular.module('JobStatusGraphWidget', ['RestServices', 'Utilities'])
|
||||
|
||||
var timeFormat, graphData = [
|
||||
{
|
||||
"color": "#00aa00",
|
||||
"color": "#60D66F",
|
||||
"key": "Successful",
|
||||
"values": data.jobs.successful
|
||||
},
|
||||
{
|
||||
"key" : "Failed" ,
|
||||
"color" : "#aa0000",
|
||||
"color" : "#ff5850",
|
||||
"values": data.jobs.failed
|
||||
}
|
||||
];
|
||||
@ -216,4 +216,4 @@ angular.module('JobStatusGraphWidget', ['RestServices', 'Utilities'])
|
||||
|
||||
};
|
||||
}
|
||||
]);
|
||||
]);
|
||||
|
||||
@ -12,14 +12,11 @@
|
||||
@blue: #1778c3; /* logo blue */
|
||||
@blue-link: #1778c3;
|
||||
@blue-dark: #2a6496; /* link hover */
|
||||
@green: #00aa00; // Ansible OK
|
||||
@grey: #A9A9A9;
|
||||
@grey-txt: #707070;
|
||||
@info: #d9edf7; /* alert info background color */
|
||||
@info-border: #bce8f1; /* alert info border color */
|
||||
@info-color: #3a87ad;
|
||||
@red: #aa0000; // Ansible Failed
|
||||
@red-hover: #AE3F3A;
|
||||
@unreachable: #FF0000;
|
||||
@changed: #FF9900; // Ansible Changed
|
||||
@skipped: #00aaaa; // Ansible Skipped
|
||||
@ -30,6 +27,10 @@
|
||||
|
||||
@tip-background: #0088CC;
|
||||
@tip-color: #fff;
|
||||
@green: #60D66F;
|
||||
@red: #ff5850;
|
||||
@red-hover: #FA8C87;
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
@ -186,6 +187,18 @@ a:focus {
|
||||
}
|
||||
}
|
||||
|
||||
// removing all the pesky outlines on buttons/links/etc.
|
||||
a:focus,
|
||||
a:active,
|
||||
button:focus,
|
||||
button:active,
|
||||
i:focus,
|
||||
i:active,
|
||||
.btn:focus,
|
||||
.btn:active:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.jqstooltip{
|
||||
background-color: black !important;
|
||||
border-radius:4px;
|
||||
@ -365,6 +378,11 @@ textarea.allowresize {
|
||||
.prepend-asterisk:before {
|
||||
content: "\002A\00A0";
|
||||
color: @red;
|
||||
margin-right: -5px;
|
||||
}
|
||||
|
||||
.prepend-asterisk--login:before {
|
||||
margin-right: -2px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
@ -656,10 +674,10 @@ dd {
|
||||
|
||||
/* Outline required fields in Red when there is an error */
|
||||
.form-control.ng-dirty.ng-invalid, .form-control.ng-dirty.ng-invalid:focus {
|
||||
border-color: rgba(204, 0, 0, 0.8);
|
||||
border-color: rgba(255, 88, 80, 0.8);
|
||||
outline: 0;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(255, 88, 80, 0.6);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(255, 88, 80, 0.6);
|
||||
}
|
||||
|
||||
/* For some reason TB 3 RC1 does not provide an input-mini */
|
||||
@ -1487,8 +1505,6 @@ input[type="checkbox"].checkbox-no-label {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#groups_table .actions .cancel { padding-right: 2px; }
|
||||
|
||||
.node-toggle, .node-no-toggle {
|
||||
/* also used on job evetns */
|
||||
float: none;
|
||||
|
||||
@ -1,25 +1,23 @@
|
||||
{
|
||||
"name": "select2",
|
||||
"version": "3.5.1",
|
||||
"description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
|
||||
"main": [
|
||||
"select2.js",
|
||||
"select2.css",
|
||||
"select2.png",
|
||||
"select2x2.png",
|
||||
"select2-spinner.gif"
|
||||
"dist/js/select2.js",
|
||||
"dist/css/select2.css"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": ">= 1.7.1"
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:select2/select2.git"
|
||||
},
|
||||
"homepage": "https://github.com/ivaynberg/select2",
|
||||
"_release": "3.5.1",
|
||||
"version": "4.0.0-rc.2",
|
||||
"_release": "4.0.0-rc.2",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "3.5.1",
|
||||
"commit": "621a3f9532357148b05efc0602f7e06b44ff9bb4"
|
||||
"tag": "4.0.0-rc.2",
|
||||
"commit": "69e2d73c42ae261b924a052e45d9b6f6dbc60fc6"
|
||||
},
|
||||
"_source": "git://github.com/ivaynberg/select2.git",
|
||||
"_target": "~3.5.1",
|
||||
"_originalSource": "select2",
|
||||
"_direct": true
|
||||
"_target": "~4.0.0",
|
||||
"_originalSource": "select2"
|
||||
}
|
||||
6
awx/ui/static/lib/select2/.editorconfig
Normal file
6
awx/ui/static/lib/select2/.editorconfig
Normal file
@ -0,0 +1,6 @@
|
||||
[*]
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
|
||||
[*.js]
|
||||
indent_size = 2
|
||||
4
awx/ui/static/lib/select2/.gitignore
vendored
4
awx/ui/static/lib/select2/.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
.idea
|
||||
|
||||
node_modules
|
||||
dist/js/i18n/build.txt
|
||||
|
||||
4
awx/ui/static/lib/select2/.jshintignore
Normal file
4
awx/ui/static/lib/select2/.jshintignore
Normal file
@ -0,0 +1,4 @@
|
||||
src/js/banner.*.js
|
||||
src/js/wrapper.*.js
|
||||
tests/vendor/*.js
|
||||
tests/helpers.js
|
||||
25
awx/ui/static/lib/select2/.jshintrc
Normal file
25
awx/ui/static/lib/select2/.jshintrc
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"bitwise": true,
|
||||
"camelcase": true,
|
||||
"curly": true,
|
||||
"es3": true,
|
||||
"eqnull": true,
|
||||
"freeze": true,
|
||||
"globals": {
|
||||
"console": false,
|
||||
"define": false,
|
||||
"document": false,
|
||||
"expect": false,
|
||||
"MockContainer": false,
|
||||
"module": false,
|
||||
"require": false,
|
||||
"test": false,
|
||||
"window": false
|
||||
},
|
||||
"indent": 2,
|
||||
"maxlen": 80,
|
||||
"noarg": true,
|
||||
"nonew": true,
|
||||
"quotmark": "single",
|
||||
"undef": true
|
||||
}
|
||||
20
awx/ui/static/lib/select2/.travis.yml
Normal file
20
awx/ui/static/lib/select2/.travis.yml
Normal file
@ -0,0 +1,20 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- 0.10
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: XMNK8GVxkwKa6oLl7nJwgg/wmY1YDk5rrMd+UXz26EDCsMDbiy1P7GhN2fEiBSLaQ7YfEuvaDcmzQxTrT0YTHp1PDzb2o9J4tIDdEkqPcv1y8xMaYDfmsN0rBPdBwZEg9H5zUgi7OdUbrGswSYxsKCE3x8EOqK89104HyOo1LN4=
|
||||
- secure: BU5BPRx6H4O3WJ509YPixjUxg+hDF3z2BVJX6NiGmKWweqvCEYFfiiHLwDEgp/ynRcF9vGVi1V4Ly1jq7f8NIajbDZ5q443XchZFYFg78K/EwD5mK6LYt16zb7+Jn0KbzwHeGRGzc9AvcEYlW6i634cSCm4n3BnqtF5PpogSzdw=
|
||||
|
||||
script:
|
||||
- grunt ci
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#select2"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
110
awx/ui/static/lib/select2/CONTRIBUTING.md
Normal file
110
awx/ui/static/lib/select2/CONTRIBUTING.md
Normal file
@ -0,0 +1,110 @@
|
||||
Contributing to Select2
|
||||
=======================
|
||||
Looking to contribute something to Select2? **Here's how you can help.**
|
||||
|
||||
Please take a moment to review this document in order to make the contribution
|
||||
process easy and effective for everyone involved.
|
||||
|
||||
Following these guidelines helps to communicate that you respect the time of
|
||||
the developers managing and developing this open source project. In return,
|
||||
they should reciprocate that respect in addressing your issue or assessing
|
||||
patches and features.
|
||||
|
||||
Using the issue tracker
|
||||
-----------------------
|
||||
When [reporting bugs][reporting-bugs] or
|
||||
[requesting features][requesting-features], the
|
||||
[issue tracker on GitHub][issue-tracker] is the recommended channel to use.
|
||||
|
||||
The issue tracker **is not** a place for support requests. The
|
||||
[mailing list][mailing-list] or [IRC channel][irc-channel] are better places to
|
||||
get help.
|
||||
|
||||
Reporting bugs with Select2
|
||||
---------------------------
|
||||
We really appreciate clear bug reports that _consistently_ show an issue
|
||||
_within Select2_.
|
||||
|
||||
The ideal bug report follows these guidelines:
|
||||
|
||||
1. **Use the [GitHub issue search][issue-search]** — Check if the issue
|
||||
has already been reported.
|
||||
2. **Check if the issue has been fixed** — Try to reproduce the problem
|
||||
using the code in the `master` branch.
|
||||
3. **Isolate the problem** — Try to create an
|
||||
[isolated test case][isolated-case] that consistently reproduces the problem.
|
||||
|
||||
Please try to be as detailed as possible in your bug report, especially if an
|
||||
isolated test case cannot be made. Some useful questions to include the answer
|
||||
to are:
|
||||
|
||||
- What steps can be used to reproduce the issue?
|
||||
- What is the bug and what is the expected outcome?
|
||||
- What browser(s) and Operating System have you tested with?
|
||||
- Does the bug happen consistently across all tested browsers?
|
||||
- What version of jQuery are you using? And what version of Select2?
|
||||
- Are you using Select2 with other plugins?
|
||||
|
||||
All of these questions will help others fix and identify any potential bugs.
|
||||
|
||||
Requesting features in Select2
|
||||
------------------------------
|
||||
Select2 is a large library that carries with it a lot of functionality. Because
|
||||
of this, many feature requests will not be implemented in the core library.
|
||||
|
||||
Before starting work on a major feature for Select2, **contact the
|
||||
[community][community] first** or you may risk spending a considerable amount of
|
||||
time on something which the project developers are not interested in bringing
|
||||
into the project.
|
||||
|
||||
Triaging issues and pull requests
|
||||
---------------------------------
|
||||
Anyone can help the project maintainers triage issues and review pull requests.
|
||||
|
||||
### Handling new issues
|
||||
|
||||
Select2 regularly receives new issues which need to be tested and organized.
|
||||
|
||||
When a new issue that comes in that is similar to another existing issue, it
|
||||
should be checked to make sure it is not a duplicate. Duplicates issues should
|
||||
be marked by replying to the issue with "Duplicate of #[issue number]" where
|
||||
`[issue number]` is the url or issue number for the existing issue. This will
|
||||
allow the project maintainers to quickly close off additional issues and keep
|
||||
the discussion focused within a single issue.
|
||||
|
||||
If you can test issues that are reported to Select2 that contain test cases and
|
||||
confirm under what conditions bugs happen, that will allow others to identify
|
||||
what causes a bug quicker.
|
||||
|
||||
### Reviewing pull requests
|
||||
|
||||
It is very common for pull requests to be opened for issues that contain a clear
|
||||
solution to the problem. These pull requests should be rigorously reviewed by
|
||||
the community before being accepted. If you are not sure about a piece of
|
||||
submitted code, or know of a better way to do something, do not hesitate to make
|
||||
a comment on the pull request.
|
||||
|
||||
### Reviving old tickets
|
||||
|
||||
If you come across tickets which have not been updated for a while, you are
|
||||
encouraged to revive them. While this can be as simple as saying `:+1:`, it is
|
||||
best if you can include more information on the issue. Common bugs and feature
|
||||
requests are more likely to be fixed, whether it is by the community or the
|
||||
developers, so keeping tickets up to date is encouraged.
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
It should also be made clear that **all code contributed to Select** must be
|
||||
licensable under the [MIT license][licensing]. Code that cannot be released
|
||||
under this license **cannot be accepted** into the project.
|
||||
|
||||
[community]: https://select2.github.io/community.html
|
||||
[reporting-bugs]: #reporting-bugs-with-select2
|
||||
[requesting-features]: #requesting-features-in-select2
|
||||
[issue-tracker]: https://github.com/select2/select2/issues
|
||||
[mailing-list]: https://github.com/select2/select2#mailing-list
|
||||
[irc-channel]: https://github.com/select2/select2#irc-channel
|
||||
[issue-search]: https://github.com/select2/select2/search?q=&type=Issues
|
||||
[isolated-case]: http://css-tricks.com/6263-reduced-test-cases/
|
||||
[licensing]: https://github.com/select2/select2/blob/master/LICENSE.md
|
||||
363
awx/ui/static/lib/select2/Gruntfile.js
vendored
Normal file
363
awx/ui/static/lib/select2/Gruntfile.js
vendored
Normal file
@ -0,0 +1,363 @@
|
||||
module.exports = function (grunt) {
|
||||
// Full list of files that must be included by RequireJS
|
||||
includes = [
|
||||
'jquery.select2',
|
||||
'almond'
|
||||
];
|
||||
|
||||
fullIncludes = [
|
||||
'jquery',
|
||||
'jquery.mousewheel',
|
||||
|
||||
'select2/compat/matcher',
|
||||
'select2/compat/initSelection',
|
||||
'select2/compat/inputData',
|
||||
'select2/compat/query',
|
||||
|
||||
'select2/dropdown/attachContainer',
|
||||
'select2/dropdown/stopPropagation',
|
||||
|
||||
'select2/selection/stopPropagation'
|
||||
].concat(includes);
|
||||
|
||||
var i18nModules = [];
|
||||
var i18nPaths = {};
|
||||
|
||||
var i18nFiles = grunt.file.expand({
|
||||
cwd: 'src/js'
|
||||
}, 'select2/i18n/*.js');
|
||||
|
||||
var testFiles = grunt.file.expand('tests/**/*.html');
|
||||
var testUrls = testFiles.map(function (filePath) {
|
||||
return 'http://localhost:9999/' + filePath;
|
||||
});
|
||||
|
||||
var testBuildNumber = "unknown";
|
||||
|
||||
if (process.env.TRAVIS_JOB_ID) {
|
||||
testBuildNumber = "travis-" + process.env.TRAVIS_JOB_ID;
|
||||
} else {
|
||||
var currentTime = new Date();
|
||||
|
||||
testBuildNumber = "manual-" + currentTime.getTime();
|
||||
}
|
||||
|
||||
for (var i = 0; i < i18nFiles.length; i++) {
|
||||
var file = i18nFiles[i];
|
||||
var name = file.split('.')[0];
|
||||
|
||||
i18nModules.push({
|
||||
name: name
|
||||
});
|
||||
|
||||
i18nPaths[name] = '../../' + name;
|
||||
}
|
||||
|
||||
var minifiedBanner = '/*! Select2 <%= package.version %> | https://github.com/select2/select2/blob/master/LICENSE.md */';
|
||||
|
||||
grunt.initConfig({
|
||||
package: grunt.file.readJSON('package.json'),
|
||||
|
||||
clean: {
|
||||
docs: ['docs/_site']
|
||||
},
|
||||
|
||||
concat: {
|
||||
'dist': {
|
||||
options: {
|
||||
banner: grunt.file.read('src/js/wrapper.start.js'),
|
||||
},
|
||||
src: [
|
||||
'dist/js/select2.js',
|
||||
'src/js/wrapper.end.js'
|
||||
],
|
||||
dest: 'dist/js/select2.js'
|
||||
},
|
||||
'dist.full': {
|
||||
options: {
|
||||
banner: grunt.file.read('src/js/wrapper.start.js'),
|
||||
},
|
||||
src: [
|
||||
'dist/js/select2.full.js',
|
||||
'src/js/wrapper.end.js'
|
||||
],
|
||||
dest: 'dist/js/select2.full.js'
|
||||
}
|
||||
},
|
||||
|
||||
connect: {
|
||||
tests: {
|
||||
options: {
|
||||
base: '.',
|
||||
hostname: '127.0.0.1',
|
||||
port: 9999
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
uglify: {
|
||||
'dist': {
|
||||
src: 'dist/js/select2.js',
|
||||
dest: 'dist/js/select2.min.js',
|
||||
options: {
|
||||
banner: minifiedBanner
|
||||
}
|
||||
},
|
||||
'dist.full': {
|
||||
src: 'dist/js/select2.full.js',
|
||||
dest: 'dist/js/select2.full.min.js',
|
||||
options: {
|
||||
banner: minifiedBanner
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
qunit: {
|
||||
all: {
|
||||
options: {
|
||||
urls: testUrls
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'saucelabs-qunit': {
|
||||
all: {
|
||||
options: {
|
||||
build: testBuildNumber,
|
||||
tags: ['tests', 'qunit'],
|
||||
urls: testUrls,
|
||||
testname: 'QUnit test for Select2',
|
||||
browsers: [
|
||||
{
|
||||
browserName: 'internet explorer',
|
||||
version: '8'
|
||||
},
|
||||
{
|
||||
browserName: 'internet explorer',
|
||||
version: '9'
|
||||
},
|
||||
{
|
||||
browserName: 'internet explorer',
|
||||
version: '10'
|
||||
},
|
||||
{
|
||||
browserName: 'internet explorer',
|
||||
version: '11'
|
||||
},
|
||||
|
||||
{
|
||||
browserName: 'firefox'
|
||||
},
|
||||
|
||||
{
|
||||
browserName: 'chrome'
|
||||
},
|
||||
|
||||
{
|
||||
browserName: 'opera',
|
||||
version: '12'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'gh-pages': {
|
||||
options: {
|
||||
base: 'docs',
|
||||
branch: 'master',
|
||||
clone: 'node_modules/grunt-gh-pages/repo',
|
||||
message: 'Updated docs with master',
|
||||
push: true,
|
||||
repo: 'git@github.com:select2/select2.github.io.git'
|
||||
},
|
||||
src: '**'
|
||||
},
|
||||
|
||||
jekyll: {
|
||||
options: {
|
||||
src: 'docs',
|
||||
dest: 'docs/_site'
|
||||
},
|
||||
build: {
|
||||
d: null
|
||||
},
|
||||
serve: {
|
||||
options: {
|
||||
serve: true,
|
||||
watch: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: true
|
||||
},
|
||||
code: {
|
||||
src: ['src/js/**/*.js']
|
||||
},
|
||||
tests: {
|
||||
src: ['tests/**/*.js']
|
||||
}
|
||||
},
|
||||
|
||||
sass: {
|
||||
dist: {
|
||||
options: {
|
||||
outputStyle: 'compressed'
|
||||
},
|
||||
files: {
|
||||
'dist/css/select2.min.css': [
|
||||
'src/scss/core.scss',
|
||||
'src/scss/theme/default/layout.css'
|
||||
]
|
||||
}
|
||||
},
|
||||
dev: {
|
||||
options: {
|
||||
outputStyle: 'nested'
|
||||
},
|
||||
files: {
|
||||
'dist/css/select2.css': [
|
||||
'src/scss/core.scss',
|
||||
'src/scss/theme/default/layout.css'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
symlink: {
|
||||
docs: {
|
||||
cwd: 'dist',
|
||||
expand: true,
|
||||
overwrite: false,
|
||||
src: [
|
||||
'*'
|
||||
],
|
||||
dest: 'docs/dist',
|
||||
filter: 'isDirectory'
|
||||
}
|
||||
},
|
||||
|
||||
requirejs: {
|
||||
'dist': {
|
||||
options: {
|
||||
baseUrl: 'src/js',
|
||||
optimize: 'none',
|
||||
name: 'select2/core',
|
||||
out: 'dist/js/select2.js',
|
||||
include: includes,
|
||||
namespace: 'S2',
|
||||
paths: {
|
||||
almond: '../../vendor/almond-0.2.9',
|
||||
jquery: 'jquery.shim'
|
||||
},
|
||||
wrap: {
|
||||
startFile: 'src/js/banner.start.js',
|
||||
endFile: 'src/js/banner.end.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
'dist.full': {
|
||||
options: {
|
||||
baseUrl: 'src/js',
|
||||
optimize: 'none',
|
||||
name: 'select2/core',
|
||||
out: 'dist/js/select2.full.js',
|
||||
include: fullIncludes,
|
||||
namespace: 'S2',
|
||||
paths: {
|
||||
almond: '../../vendor/almond-0.2.9',
|
||||
jquery: 'jquery.shim',
|
||||
'jquery.mousewheel': '../../vendor/jquery.mousewheel'
|
||||
},
|
||||
wrap: {
|
||||
startFile: 'src/js/banner.start.js',
|
||||
endFile: 'src/js/banner.end.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
'i18n': {
|
||||
options: {
|
||||
baseUrl: 'src/js/select2/i18n',
|
||||
dir: 'dist/js/i18n',
|
||||
paths: i18nPaths,
|
||||
modules: i18nModules,
|
||||
namespace: 'S2',
|
||||
wrap: {
|
||||
start: minifiedBanner + grunt.file.read('src/js/banner.start.js'),
|
||||
end: grunt.file.read('src/js/banner.end.js')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
js: {
|
||||
files: [
|
||||
'src/js/select2/**/*.js',
|
||||
'tests/**/*.js'
|
||||
],
|
||||
tasks: [
|
||||
'compile',
|
||||
'test',
|
||||
'minify'
|
||||
]
|
||||
},
|
||||
css: {
|
||||
files: [
|
||||
'src/scss/**/*.scss'
|
||||
],
|
||||
tasks: [
|
||||
'compile',
|
||||
'minify'
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-qunit');
|
||||
grunt.loadNpmTasks('grunt-contrib-requirejs');
|
||||
grunt.loadNpmTasks('grunt-contrib-symlink');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
grunt.loadNpmTasks('grunt-gh-pages');
|
||||
grunt.loadNpmTasks('grunt-jekyll');
|
||||
grunt.loadNpmTasks('grunt-saucelabs');
|
||||
grunt.loadNpmTasks('grunt-sass');
|
||||
|
||||
grunt.registerTask('default', ['compile', 'test', 'minify']);
|
||||
|
||||
grunt.registerTask('compile', [
|
||||
'requirejs:dist', 'requirejs:dist.full', 'requirejs:i18n',
|
||||
'concat:dist', 'concat:dist.full',
|
||||
'sass:dev'
|
||||
]);
|
||||
grunt.registerTask('minify', ['uglify', 'sass:dist']);
|
||||
grunt.registerTask('test', ['connect:tests', 'qunit', 'jshint']);
|
||||
|
||||
var ciTasks = [];
|
||||
|
||||
ciTasks.push('compile')
|
||||
ciTasks.push('connect:tests');
|
||||
|
||||
// Can't run Sauce Labs tests in pull requests
|
||||
if (process.env.TRAVIS_PULL_REQUEST == 'false') {
|
||||
ciTasks.push('saucelabs-qunit');
|
||||
}
|
||||
|
||||
ciTasks.push('qunit');
|
||||
ciTasks.push('jshint');
|
||||
|
||||
grunt.registerTask('ci', ciTasks);
|
||||
|
||||
grunt.registerTask('docs', ['symlink:docs', 'jekyll:serve']);
|
||||
|
||||
grunt.registerTask('docs-release', ['default', 'clean:docs', 'gh-pages']);
|
||||
};
|
||||
21
awx/ui/static/lib/select2/LICENSE.md
Normal file
21
awx/ui/static/lib/select2/LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2015 Kevin Brown, Igor Vaynberg, and Select2 contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@ -1,20 +1,26 @@
|
||||
Select2
|
||||
=======
|
||||
[![Build Status][travis-ci-image]][travis-ci-status]
|
||||
|
||||
Select2 is a jQuery-based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
|
||||
Select2 is a jQuery-based replacement for select boxes. It supports searching,
|
||||
remote data sets, and pagination of results.
|
||||
|
||||
To get started, checkout examples and documentation at http://ivaynberg.github.com/select2
|
||||
To get started, checkout examples and documentation at
|
||||
https://select2.github.io/
|
||||
|
||||
Use cases
|
||||
---------
|
||||
|
||||
* Enhancing native selects with search.
|
||||
* Enhancing native selects with a better multi-select interface.
|
||||
* Loading data from JavaScript: easily load items via ajax and have them searchable.
|
||||
* Nesting optgroups: native selects only support one level of nested. Select2 does not have this restriction.
|
||||
* Loading data from JavaScript: easily load items via AJAX and have them
|
||||
searchable.
|
||||
* Nesting optgroups: native selects only support one level of nesting. Select2
|
||||
does not have this restriction.
|
||||
* Tagging: ability to add new items on the fly.
|
||||
* Working with large, remote datasets: ability to partially load a dataset based on the search term.
|
||||
* Paging of large datasets: easy support for loading more pages when the results are scrolled to the end.
|
||||
* Working with large, remote datasets: ability to partially load a dataset based
|
||||
on the search term.
|
||||
* Paging of large datasets: easy support for loading more pages when the results
|
||||
are scrolled to the end.
|
||||
* Templating: support for custom rendering of results and selections.
|
||||
|
||||
Browser compatibility
|
||||
@ -24,76 +30,76 @@ Browser compatibility
|
||||
* Firefox 10+
|
||||
* Safari 3+
|
||||
* Opera 10.6+
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
You can source Select2 directly from a [CDN like JSDliver](http://www.jsdelivr.com/#!select2), [download it from this GitHub repo](https://github.com/ivaynberg/select2/tags), or use one of the integrations below.
|
||||
You can source Select2 directly from a CDN like [JSDliver][jsdelivr] or
|
||||
[CDNJS][cdnjs], [download it from this GitHub repo][releases], or use one of
|
||||
the integrations below.
|
||||
|
||||
Integrations
|
||||
------------
|
||||
|
||||
* [Wicket-Select2](https://github.com/ivaynberg/wicket-select2) (Java / [Apache Wicket](http://wicket.apache.org))
|
||||
* [select2-rails](https://github.com/argerim/select2-rails) (Ruby on Rails)
|
||||
* [AngularUI](http://angular-ui.github.com/#directives-select2) ([AngularJS](angularjs.org))
|
||||
* [Django](https://github.com/applegrew/django-select2)
|
||||
* [Symfony](https://github.com/19Gerhard85/sfSelect2WidgetsPlugin)
|
||||
* [Symfony2](https://github.com/avocode/FormExtensions)
|
||||
* [Bootstrap 2](https://github.com/t0m/select2-bootstrap-css) and [Bootstrap 3](https://github.com/t0m/select2-bootstrap-css/tree/bootstrap3) (CSS skins)
|
||||
* [Meteor](https://github.com/nate-strauser/meteor-select2) (modern reactive JavaScript framework; + [Bootstrap 3 skin](https://github.com/esperadomedia/meteor-select2-bootstrap3-css/))
|
||||
* [Meteor](https://jquery-select2.meteor.com)
|
||||
* [Yii 2.x](http://demos.krajee.com/widgets#select2)
|
||||
* [Yii 1.x](https://github.com/tonybolzan/yii-select2)
|
||||
* [AtmosphereJS](https://atmospherejs.com/package/jquery-select2)
|
||||
|
||||
### Example Integrations
|
||||
|
||||
* [Knockout.js](https://github.com/ivaynberg/select2/wiki/Knockout.js-Integration)
|
||||
* [Socket.IO](https://github.com/ivaynberg/select2/wiki/Socket.IO-Integration)
|
||||
* [PHP](https://github.com/ivaynberg/select2/wiki/PHP-Example)
|
||||
* [.Net MVC] (https://github.com/ivaynberg/select2/wiki/.Net-MVC-Example)
|
||||
* [Wicket-Select2][wicket-select2] (Java / [Apache Wicket][wicket])
|
||||
* [select2-rails][select2-rails] (Ruby on Rails)
|
||||
* [AngularUI][angularui-select] ([AngularJS][angularjs])
|
||||
* [Django][django-select2]
|
||||
* [Symfony][symfony-select2]
|
||||
* [Symfony2][symfony2-select2]
|
||||
* [Bootstrap 2][bootstrap2-select2] and [Bootstrap 3][bootstrap3-select2]
|
||||
(CSS skins)
|
||||
* [Meteor][meteor-select2] ([Bootstrap 3 skin][meteor-select2-bootstrap3])
|
||||
* [Meteor][meteor-select2-alt]
|
||||
* [Yii 2.x][yii2-select2]
|
||||
* [Yii 1.x][yii-select2]
|
||||
* [AtmosphereJS][atmospherejs-select2]
|
||||
|
||||
Internationalization (i18n)
|
||||
---------------------------
|
||||
|
||||
Select2 supports multiple languages by simply including the right language JS
|
||||
file (`select2_locale_it.js`, `select2_locale_nl.js`, etc.) after `select2.js`.
|
||||
file (`dist/js/i18n/it.js`, `dist/js/i18n/nl.js`, etc.) after
|
||||
`dist/js/select2.js`.
|
||||
|
||||
Missing a language? Just copy `select2_locale_en.js.template`, translate
|
||||
it, and make a pull request back to Select2 here on GitHub.
|
||||
Missing a language? Just copy `src/js/select2/i18n/en.js`, translate it, and
|
||||
make a pull request back to Select2 here on GitHub.
|
||||
|
||||
Bug tracker
|
||||
-----------
|
||||
|
||||
Have a bug? Please create an issue here on GitHub!
|
||||
|
||||
https://github.com/ivaynberg/select2/issues
|
||||
|
||||
Mailing list
|
||||
------------
|
||||
|
||||
Have a question? Ask on our mailing list!
|
||||
|
||||
select2@googlegroups.com
|
||||
|
||||
https://groups.google.com/d/forum/select2
|
||||
Documentation
|
||||
-------------
|
||||
The documentation for Select2 is available
|
||||
[through GitHub Pages][documentation] and is located within this repository
|
||||
in the [`docs` folder][documentation-folder].
|
||||
|
||||
Community
|
||||
---------
|
||||
You can find out about the different ways to get in touch with the Select2
|
||||
community at the [Select2 community page][community].
|
||||
|
||||
Copyright and license
|
||||
---------------------
|
||||
The license is available within the repository in the [LICENSE][license] file.
|
||||
|
||||
Copyright 2012 Igor Vaynberg
|
||||
|
||||
This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
|
||||
General Public License version 2 (the "GPL License"). You may choose either license to govern your
|
||||
use of this software only upon the condition that you accept all of the terms of either the Apache
|
||||
License or the GPL License.
|
||||
|
||||
You may obtain a copy of the Apache License and the GPL License in the LICENSE file, or at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the Apache License
|
||||
or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
either express or implied. See the Apache License and the GPL License for the specific language governing
|
||||
permissions and limitations under the Apache License and the GPL License.
|
||||
[angularjs]: https://angularjs.org/
|
||||
[angularui-select]: http://angular-ui.github.io/#ui-select
|
||||
[atmospherejs-select2]: https://atmospherejs.com/package/jquery-select2
|
||||
[bootstrap2-select2]: https://github.com/t0m/select2-bootstrap-css
|
||||
[bootstrap3-select2]: https://github.com/t0m/select2-bootstrap-css/tree/bootstrap3
|
||||
[cdnjs]: http://www.cdnjs.com/libraries/select2
|
||||
[community]: https://select2.github.io/community.html
|
||||
[django-select2]: https://github.com/applegrew/django-select2
|
||||
[documentation]: https://select2.github.io/
|
||||
[documentation-folder]: https://github.com/select2/select2/tree/master/docs
|
||||
[freenode]: https://freenode.net/
|
||||
[jsdelivr]: http://www.jsdelivr.com/#!select2
|
||||
[license]: LICENSE.md
|
||||
[meteor-select2]: https://github.com/nate-strauser/meteor-select2
|
||||
[meteor-select2-alt]: https://jquery-select2.meteor.com
|
||||
[meteor-select2-bootstrap3]: https://github.com/zimme/meteor-select2-bootstrap3-css/
|
||||
[releases]: https://github.com/select2/select2/releases
|
||||
[select2-rails]: https://github.com/argerim/select2-rails
|
||||
[symfony-select2]: https://github.com/19Gerhard85/sfSelect2WidgetsPlugin
|
||||
[symfony2-select2]: https://github.com/avocode/FormExtensions
|
||||
[travis-ci-image]: https://travis-ci.org/select2/select2.svg?branch=master
|
||||
[travis-ci-status]: https://travis-ci.org/select2/select2
|
||||
[wicket]: http://wicket.apache.org
|
||||
[wicket-select2]: https://github.com/ivaynberg/wicket-select2
|
||||
[yii-select2]: https://github.com/tonybolzan/yii-select2
|
||||
[yii2-select2]: http://demos.krajee.com/widgets#select2
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
{
|
||||
"name": "select2",
|
||||
"version": "3.5.1",
|
||||
"main": ["select2.js", "select2.css", "select2.png", "select2x2.png", "select2-spinner.gif"],
|
||||
"dependencies": {
|
||||
"jquery": ">= 1.7.1"
|
||||
"description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
|
||||
"main": [
|
||||
"dist/js/select2.js",
|
||||
"dist/css/select2.css"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:select2/select2.git"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,66 +1,19 @@
|
||||
{
|
||||
"name": "select2",
|
||||
"repo": "ivaynberg/select2",
|
||||
"repo": "select/select2",
|
||||
"description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
|
||||
"version": "3.5.1",
|
||||
"demo": "http://ivaynberg.github.io/select2/",
|
||||
"version": "4.0.0-rc.2",
|
||||
"demo": "https://select2.github.io/",
|
||||
"keywords": [
|
||||
"jquery"
|
||||
],
|
||||
"main": "select2.js",
|
||||
"main": "dist/js/select2.js",
|
||||
"styles": [
|
||||
"select2.css",
|
||||
"select2-bootstrap.css"
|
||||
"dist/css/select2.css"
|
||||
],
|
||||
"scripts": [
|
||||
"select2.js",
|
||||
"select2_locale_ar.js",
|
||||
"select2_locale_bg.js",
|
||||
"select2_locale_ca.js",
|
||||
"select2_locale_cs.js",
|
||||
"select2_locale_da.js",
|
||||
"select2_locale_de.js",
|
||||
"select2_locale_el.js",
|
||||
"select2_locale_es.js",
|
||||
"select2_locale_et.js",
|
||||
"select2_locale_eu.js",
|
||||
"select2_locale_fa.js",
|
||||
"select2_locale_fi.js",
|
||||
"select2_locale_fr.js",
|
||||
"select2_locale_gl.js",
|
||||
"select2_locale_he.js",
|
||||
"select2_locale_hr.js",
|
||||
"select2_locale_hu.js",
|
||||
"select2_locale_id.js",
|
||||
"select2_locale_is.js",
|
||||
"select2_locale_it.js",
|
||||
"select2_locale_ja.js",
|
||||
"select2_locale_ka.js",
|
||||
"select2_locale_ko.js",
|
||||
"select2_locale_lt.js",
|
||||
"select2_locale_lv.js",
|
||||
"select2_locale_mk.js",
|
||||
"select2_locale_ms.js",
|
||||
"select2_locale_nl.js",
|
||||
"select2_locale_no.js",
|
||||
"select2_locale_pl.js",
|
||||
"select2_locale_pt-BR.js",
|
||||
"select2_locale_pt-PT.js",
|
||||
"select2_locale_ro.js",
|
||||
"select2_locale_ru.js",
|
||||
"select2_locale_sk.js",
|
||||
"select2_locale_sv.js",
|
||||
"select2_locale_th.js",
|
||||
"select2_locale_tr.js",
|
||||
"select2_locale_uk.js",
|
||||
"select2_locale_vi.js",
|
||||
"select2_locale_zh-CN.js",
|
||||
"select2_locale_zh-TW.js"
|
||||
],
|
||||
"images": [
|
||||
"select2-spinner.gif",
|
||||
"select2.png",
|
||||
"select2x2.png"
|
||||
"dist/js/select2.js",
|
||||
"dist/js/i18n/*.js"
|
||||
],
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@ -1,28 +1,21 @@
|
||||
{
|
||||
"name":
|
||||
"ivaynberg/select2",
|
||||
"name": "select2/select2",
|
||||
"description": "Select2 is a jQuery based replacement for select boxes.",
|
||||
"version": "3.5.1",
|
||||
"type": "component",
|
||||
"homepage": "http://ivaynberg.github.io/select2/",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://select2.github.io/",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"robloach/component-installer": "*",
|
||||
"components/jquery": ">=1.7.1"
|
||||
"robloach/component-installer": "*"
|
||||
},
|
||||
"extra": {
|
||||
"component": {
|
||||
"scripts": [
|
||||
"select2.js"
|
||||
"dist/js/select2.js"
|
||||
],
|
||||
"files": [
|
||||
"select2.js",
|
||||
"select2_locale_*.js",
|
||||
"select2.css",
|
||||
"select2-bootstrap.css",
|
||||
"select2-spinner.gif",
|
||||
"select2.png",
|
||||
"select2x2.png"
|
||||
"dist/js/select2.js",
|
||||
"dist/js/i18n/*.js",
|
||||
"dist/css/select2.css"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
557
awx/ui/static/lib/select2/dist/css/select2-bootstrap.css
vendored
Normal file
557
awx/ui/static/lib/select2/dist/css/select2-bootstrap.css
vendored
Normal file
@ -0,0 +1,557 @@
|
||||
/*! Select2 Bootstrap Theme v0.1.0-beta.1 | MIT License | github.com/fk/select2-bootstrap-theme */
|
||||
.select2-container--bootstrap {
|
||||
display: block;
|
||||
/*------------------------------------*\
|
||||
#COMMON STYLES
|
||||
\*------------------------------------*/
|
||||
/**
|
||||
* Search field in the Select2 dropdown.
|
||||
*/
|
||||
/**
|
||||
* No outline for all search fields - in the dropdown
|
||||
* and inline in multi Select2s.
|
||||
*/
|
||||
/**
|
||||
* Adjust Select2's choices hover and selected styles to match
|
||||
* Bootstrap 3's default dropdown styles.
|
||||
*
|
||||
* @see http://getbootstrap.com/components/#dropdowns
|
||||
*/
|
||||
/**
|
||||
* Address disabled Select2 styles.
|
||||
*
|
||||
* @see https://select2.github.io/examples.html#disabled
|
||||
* @see http://getbootstrap.com/css/#forms-control-disabled
|
||||
*/
|
||||
/*------------------------------------*\
|
||||
#DROPDOWN
|
||||
\*------------------------------------*/
|
||||
/**
|
||||
* Dropdown border color and box-shadow.
|
||||
*/
|
||||
/**
|
||||
* Limit the dropdown height.
|
||||
*/
|
||||
/*------------------------------------*\
|
||||
#SINGLE SELECT2
|
||||
\*------------------------------------*/
|
||||
/*------------------------------------*\
|
||||
#MULTIPLE SELECT2
|
||||
\*------------------------------------*/
|
||||
/**
|
||||
* Address Bootstrap control sizing classes
|
||||
*
|
||||
* 1. Reset Bootstrap defaults.
|
||||
* 2. Adjust the dropdown arrow button icon position.
|
||||
*
|
||||
* @see http://getbootstrap.com/css/#forms-control-sizes
|
||||
*/
|
||||
/* 1 */
|
||||
/*------------------------------------*\
|
||||
#RTL SUPPORT
|
||||
\*------------------------------------*/
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection {
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
color: #555555;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
outline: 0;
|
||||
}
|
||||
.select2-container--bootstrap .select2-search--dropdown .select2-search__field {
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
color: #555555;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-search__field {
|
||||
outline: 0;
|
||||
/* Firefox 18- */
|
||||
/**
|
||||
* Firefox 19+
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/24236240/color-for-styled-placeholder-text-is-muted-in-firefox
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap .select2-search__field::-webkit-input-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.select2-container--bootstrap .select2-search__field:-moz-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.select2-container--bootstrap .select2-search__field::-moz-placeholder {
|
||||
color: #999;
|
||||
opacity: 1;
|
||||
}
|
||||
.select2-container--bootstrap .select2-search__field:-ms-input-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option {
|
||||
/**
|
||||
* Disabled results.
|
||||
*
|
||||
* @see https://select2.github.io/examples.html#disabled-results
|
||||
*/
|
||||
/**
|
||||
* Hover state.
|
||||
*/
|
||||
/**
|
||||
* Selected state.
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option[role=group] {
|
||||
padding: 0;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option[aria-disabled=true] {
|
||||
color: #777777;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option[aria-selected=true] {
|
||||
background-color: #f5f5f5;
|
||||
color: #262626;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #337ab7;
|
||||
color: #fff;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option .select2-results__option {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__group {
|
||||
padding-left: 0;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -12px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -24px;
|
||||
padding-left: 36px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -36px;
|
||||
padding-left: 48px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -48px;
|
||||
padding-left: 60px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -60px;
|
||||
padding-left: 72px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results__group {
|
||||
color: #777777;
|
||||
display: block;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
line-height: 1.42857143;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--open {
|
||||
/**
|
||||
* Handle border radii of the container when the dropdown is showing.
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--open .select2-selection {
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
|
||||
-webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
|
||||
-o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
|
||||
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
|
||||
border-color: #66afe9;
|
||||
/**
|
||||
* Make the dropdown arrow point up while the dropdown is visible.
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--open .select2-selection .select2-selection__arrow b {
|
||||
border-color: transparent transparent #999 transparent;
|
||||
border-width: 0 4px 4px 4px;
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--open.select2-container--below .select2-selection {
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--open.select2-container--above .select2-selection {
|
||||
border-top-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--disabled .select2-selection,
|
||||
.select2-container--bootstrap.select2-container--disabled .select2-search__field {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--disabled .select2-selection,
|
||||
.select2-container--bootstrap.select2-container--disabled .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
.select2-container--bootstrap.select2-container--disabled .select2-selection__clear,
|
||||
.select2-container--bootstrap.select2-container--disabled .select2-selection--multiple .select2-selection__choice__remove {
|
||||
display: none;
|
||||
}
|
||||
.select2-container--bootstrap .select2-dropdown {
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
border-color: #66afe9;
|
||||
overflow-x: hidden;
|
||||
margin-top: -1px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-dropdown--above {
|
||||
margin-top: 1px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--single {
|
||||
height: 34px;
|
||||
line-height: 1.42857143;
|
||||
padding: 6px 24px 6px 12px;
|
||||
/**
|
||||
* Clear the selection.
|
||||
*/
|
||||
/**
|
||||
* Adjust the single Select2's dropdown arrow button appearance.
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--single .select2-selection__clear {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--single .select2-selection__clear:hover {
|
||||
color: #333;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--single .select2-selection__arrow {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 12px;
|
||||
top: 0;
|
||||
width: 4px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #999 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 4px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 0;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--single .select2-selection__rendered {
|
||||
color: #555555;
|
||||
padding: 0;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--multiple {
|
||||
min-height: 34px;
|
||||
/**
|
||||
* Make Multi Select2's choices match Bootstrap 3's default button styles.
|
||||
*/
|
||||
/**
|
||||
* Minus 2px borders.
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--multiple .select2-selection__rendered {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
line-height: 1.42857143;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--multiple .select2-selection__placeholder {
|
||||
color: #999;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
|
||||
color: #555555;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin: 5px 0 0 6px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field {
|
||||
background: transparent;
|
||||
padding: 0 12px;
|
||||
height: 32px;
|
||||
line-height: 1.42857143;
|
||||
margin-top: 0;
|
||||
min-width: 5em;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 3px;
|
||||
}
|
||||
.select2-container--bootstrap .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #333;
|
||||
}
|
||||
.select2-container--bootstrap.input-sm, .select2-container--bootstrap.input-lg {
|
||||
border-radius: 0;
|
||||
font-size: 12px;
|
||||
height: auto;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
}
|
||||
.select2-container--bootstrap.input-sm .select2-selection--single, .input-group-sm .select2-container--bootstrap .select2-selection--single, .form-group-sm .select2-container--bootstrap .select2-selection--single {
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
height: 30px;
|
||||
line-height: 1.5;
|
||||
padding: 5px 22px 5px 10px;
|
||||
/* 2 */
|
||||
}
|
||||
.select2-container--bootstrap.input-sm .select2-selection--single .select2-selection__arrow b, .input-group-sm .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b, .form-group-sm .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b {
|
||||
margin-left: -5px;
|
||||
}
|
||||
.select2-container--bootstrap.input-sm .select2-selection--multiple, .input-group-sm .select2-container--bootstrap .select2-selection--multiple, .form-group-sm .select2-container--bootstrap .select2-selection--multiple {
|
||||
min-height: 30px;
|
||||
}
|
||||
.select2-container--bootstrap.input-sm .select2-selection--multiple .select2-selection__choice, .input-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice, .form-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
margin: 4px 0 0 5px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.select2-container--bootstrap.input-sm .select2-selection--multiple .select2-search--inline .select2-search__field, .input-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field, .form-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field {
|
||||
padding: 0 10px;
|
||||
font-size: 12px;
|
||||
height: 28px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.select2-container--bootstrap.input-lg .select2-selection--single, .input-group-lg .select2-container--bootstrap .select2-selection--single, .form-group-lg .select2-container--bootstrap .select2-selection--single {
|
||||
border-radius: 6px;
|
||||
font-size: 18px;
|
||||
height: 46px;
|
||||
line-height: 1.3333333;
|
||||
padding: 10px 31px 10px 16px;
|
||||
/* 1 */
|
||||
}
|
||||
.select2-container--bootstrap.input-lg .select2-selection--single .select2-selection__arrow, .input-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow, .form-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow {
|
||||
width: 5px;
|
||||
}
|
||||
.select2-container--bootstrap.input-lg .select2-selection--single .select2-selection__arrow b, .input-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b, .form-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b {
|
||||
border-width: 5px 5px 0 5px;
|
||||
margin-left: -5px;
|
||||
margin-left: -10px;
|
||||
margin-top: -2.5px;
|
||||
}
|
||||
.select2-container--bootstrap.input-lg .select2-selection--multiple, .input-group-lg .select2-container--bootstrap .select2-selection--multiple, .form-group-lg .select2-container--bootstrap .select2-selection--multiple {
|
||||
min-height: 46px;
|
||||
}
|
||||
.select2-container--bootstrap.input-lg .select2-selection--multiple .select2-selection__choice, .input-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice, .form-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
|
||||
font-size: 18px;
|
||||
line-height: 1.3333333;
|
||||
border-radius: 4px;
|
||||
margin: 9px 0 0 8px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.select2-container--bootstrap.input-lg .select2-selection--multiple .select2-search--inline .select2-search__field, .input-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field, .form-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field {
|
||||
padding: 0 16px;
|
||||
font-size: 18px;
|
||||
height: 44px;
|
||||
line-height: 1.3333333;
|
||||
}
|
||||
.select2-container--bootstrap.input-lg.select2-container--open .select2-selection--single {
|
||||
/**
|
||||
* Make the dropdown arrow point up while the dropdown is visible.
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap.input-lg.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #999 transparent;
|
||||
border-width: 0 5px 5px 5px;
|
||||
}
|
||||
.input-group-lg .select2-container--bootstrap.select2-container--open .select2-selection--single {
|
||||
/**
|
||||
* Make the dropdown arrow point up while the dropdown is visible.
|
||||
*/
|
||||
}
|
||||
.input-group-lg .select2-container--bootstrap.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #999 transparent;
|
||||
border-width: 0 5px 5px 5px;
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] {
|
||||
/**
|
||||
* Single Select2
|
||||
*
|
||||
* 1. Makes sure that .select2-selection__placeholder is positioned
|
||||
* correctly.
|
||||
*/
|
||||
/**
|
||||
* Multiple Select2
|
||||
*/
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--single {
|
||||
padding-left: 24px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__rendered {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
text-align: right;
|
||||
/* 1 */
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left;
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
left: 12px;
|
||||
right: auto;
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__arrow b {
|
||||
margin-left: 0;
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder {
|
||||
float: right;
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 0;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
/*------------------------------------*\
|
||||
#ADDITIONAL GOODIES
|
||||
\*------------------------------------*/
|
||||
/**
|
||||
* Address Bootstrap's validation states
|
||||
*
|
||||
* If a Select2 widget parent has one of Bootstrap's validation state modifier
|
||||
* classes, adjust Select2's border colors and focus states accordingly.
|
||||
* You may apply said classes to the Select2 dropdown (body > .select2-container)
|
||||
* via JavaScript match Bootstraps' to make its styles match.
|
||||
*
|
||||
* @see http://getbootstrap.com/css/#forms-control-validation
|
||||
*/
|
||||
.has-warning .select2-dropdown,
|
||||
.has-warning .select2-selection {
|
||||
border-color: #8a6d3b;
|
||||
}
|
||||
.has-warning .select2-container--open .select2-selection {
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
|
||||
border-color: #66512c;
|
||||
}
|
||||
.has-warning.select2-drop-active {
|
||||
border-color: #66512c;
|
||||
}
|
||||
.has-warning.select2-drop-active.select2-drop.select2-drop-above {
|
||||
border-top-color: #66512c;
|
||||
}
|
||||
|
||||
.has-error .select2-dropdown,
|
||||
.has-error .select2-selection {
|
||||
border-color: #a94442;
|
||||
}
|
||||
.has-error .select2-container--open .select2-selection {
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
|
||||
border-color: #843534;
|
||||
}
|
||||
.has-error.select2-drop-active {
|
||||
border-color: #843534;
|
||||
}
|
||||
.has-error.select2-drop-active.select2-drop.select2-drop-above {
|
||||
border-top-color: #843534;
|
||||
}
|
||||
|
||||
.has-success .select2-dropdown,
|
||||
.has-success .select2-selection {
|
||||
border-color: #3c763d;
|
||||
}
|
||||
.has-success .select2-container--open .select2-selection {
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
|
||||
border-color: #2b542c;
|
||||
}
|
||||
.has-success.select2-drop-active {
|
||||
border-color: #2b542c;
|
||||
}
|
||||
.has-success.select2-drop-active.select2-drop.select2-drop-above {
|
||||
border-top-color: #2b542c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select2 widgets in Bootstrap Input Groups
|
||||
*
|
||||
* When Select2 widgets are combined with other elements using Bootstraps
|
||||
* "Input Group" component, we don't want specific edges of the Select2
|
||||
* container to have a border-radius.
|
||||
*
|
||||
* Use .select2-bootstrap-prepend and .select2-bootstrap-append on
|
||||
* a Bootstrap 3 .input-group to let the contained Select2 widget know which
|
||||
* edges should not be rounded as they are directly followed by another element.
|
||||
*
|
||||
* @see http://getbootstrap.com/components/#input-groups
|
||||
*/
|
||||
/**
|
||||
* Mimick Bootstraps .input-group .form-control styles.
|
||||
*
|
||||
* @see https://github.com/twbs/bootstrap/blob/master/less/input-groups.less
|
||||
*/
|
||||
.input-group .select2-container--bootstrap {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
float: left;
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.input-group.select2-bootstrap-prepend .select2-container--bootstrap .select2-selection {
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
.input-group.select2-bootstrap-append .select2-container--bootstrap .select2-selection {
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust alignment of Bootstrap buttons in Bootstrap Input Groups to address
|
||||
* Multi Select2's height which - depending on how many elements have been selected -
|
||||
* may grown higher than their initial size.
|
||||
*
|
||||
* @see http://getbootstrap.com/components/#input-groups
|
||||
*/
|
||||
.select2-bootstrap-append .select2-container--bootstrap,
|
||||
.select2-bootstrap-append .input-group-btn,
|
||||
.select2-bootstrap-append .input-group-btn .btn,
|
||||
.select2-bootstrap-prepend .select2-container--bootstrap,
|
||||
.select2-bootstrap-prepend .input-group-btn,
|
||||
.select2-bootstrap-prepend .input-group-btn .btn {
|
||||
vertical-align: top;
|
||||
}
|
||||
421
awx/ui/static/lib/select2/dist/css/select2.css
vendored
Normal file
421
awx/ui/static/lib/select2/dist/css/select2.css
vendored
Normal file
@ -0,0 +1,421 @@
|
||||
.select2-container {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
vertical-align: middle; }
|
||||
.select2-container .select2-selection--single {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 28px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--single .select2-selection__rendered {
|
||||
display: block;
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
|
||||
padding-right: 8px;
|
||||
padding-left: 20px; }
|
||||
.select2-container .select2-selection--multiple {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
min-height: 32px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-left: 8px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-search--inline {
|
||||
float: left; }
|
||||
.select2-container .select2-search--inline .select2-search__field {
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
margin-top: 5px; }
|
||||
.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
|
||||
.select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -100000px;
|
||||
width: 100%;
|
||||
z-index: 1051; }
|
||||
|
||||
.select2-results {
|
||||
display: block; }
|
||||
|
||||
.select2-results__options {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.select2-results__option {
|
||||
padding: 6px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-results__option[aria-selected] {
|
||||
cursor: pointer; }
|
||||
|
||||
.select2-container--open .select2-dropdown {
|
||||
left: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--above {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--below {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-search--dropdown {
|
||||
display: block;
|
||||
padding: 4px; }
|
||||
.select2-search--dropdown .select2-search__field {
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
.select2-search--dropdown.select2-search--hide {
|
||||
display: none; }
|
||||
|
||||
.select2-close-mask {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
opacity: 0;
|
||||
z-index: 99;
|
||||
background-color: #fff;
|
||||
filter: alpha(opacity=0); }
|
||||
|
||||
.select2-container--default .select2-selection--single {
|
||||
background-color: #fff;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
|
||||
display: none; }
|
||||
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px;
|
||||
width: 100%; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
float: left; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #333; }
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder {
|
||||
float: right; }
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
.select2-container--default.select2-container--focus .select2-selection--multiple {
|
||||
border: solid black 1px;
|
||||
outline: 0; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection--multiple {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
|
||||
display: none; }
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa; }
|
||||
.select2-container--default .select2-search--inline .select2-search__field {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: 0; }
|
||||
.select2-container--default .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
.select2-container--default .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
.select2-container--default .select2-results__option[aria-disabled=true] {
|
||||
color: #999; }
|
||||
.select2-container--default .select2-results__option[aria-selected=true] {
|
||||
background-color: #ddd; }
|
||||
.select2-container--default .select2-results__option .select2-results__option {
|
||||
padding-left: 1em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__group {
|
||||
padding-left: 0; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -1em;
|
||||
padding-left: 2em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -2em;
|
||||
padding-left: 3em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -3em;
|
||||
padding-left: 4em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -4em;
|
||||
padding-left: 5em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -5em;
|
||||
padding-left: 6em; }
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #5897fb;
|
||||
color: white; }
|
||||
.select2-container--default .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic .select2-selection--single {
|
||||
background-color: #f6f6f6;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
outline: 0;
|
||||
background-image: -webkit-linear-gradient(top, #ffffff 50%, #eeeeee 100%);
|
||||
background-image: -o-linear-gradient(top, #ffffff 50%, #eeeeee 100%);
|
||||
background-image: linear-gradient(to bottom, #ffffff 50%, #eeeeee 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-right: 10px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow {
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
border-left: 1px solid #aaa;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#cccccc', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
border: none;
|
||||
border-right: 1px solid #aaa;
|
||||
border-radius: 0;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
|
||||
background: transparent;
|
||||
border: none; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, #ffffff 0%, #eeeeee 50%);
|
||||
background-image: -o-linear-gradient(top, #ffffff 0%, #eeeeee 50%);
|
||||
background-image: linear-gradient(to bottom, #ffffff 0%, #eeeeee 50%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); }
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #ffffff 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, #ffffff 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, #ffffff 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text;
|
||||
outline: 0; }
|
||||
.select2-container--classic .select2-selection--multiple:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__rendered {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__clear {
|
||||
display: none; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #555; }
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
float: right; }
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--multiple {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
.select2-container--classic .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa;
|
||||
outline: 0; }
|
||||
.select2-container--classic .select2-search--inline .select2-search__field {
|
||||
outline: 0; }
|
||||
.select2-container--classic .select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid transparent; }
|
||||
.select2-container--classic .select2-dropdown--above {
|
||||
border-bottom: none; }
|
||||
.select2-container--classic .select2-dropdown--below {
|
||||
border-top: none; }
|
||||
.select2-container--classic .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
.select2-container--classic .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
.select2-container--classic .select2-results__option[aria-disabled=true] {
|
||||
color: grey; }
|
||||
.select2-container--classic .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #3875d7;
|
||||
color: white; }
|
||||
.select2-container--classic .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
.select2-container--classic.select2-container--open .select2-dropdown {
|
||||
border-color: #5897fb; }
|
||||
1
awx/ui/static/lib/select2/dist/css/select2.min.css
vendored
Normal file
1
awx/ui/static/lib/select2/dist/css/select2.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
3
awx/ui/static/lib/select2/dist/js/i18n/az.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/az.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/az",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return t+" simvol silin"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(e){return"Sadəcə "+e.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/bg.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/bg.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bg",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Моля въведете с "+t+" по-малко символ";return t>1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/ca.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/ca.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/cs.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/cs.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím zadejte o jeden znak méně":n<=4?"Prosím zadejte o "+e(n,!0)+" znaky méně":"Prosím zadejte o "+n+" znaků méně"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím zadejte ještě jeden znak":n<=4?"Prosím zadejte ještě další "+e(n,!0)+" znaky":"Prosím zadejte ještě dalších "+n+" znaků"},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky":"Můžete zvolit maximálně "+n+" položek"},noResults:function(){return"Nenalezeny žádné položky"},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/da.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/da.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Angiv venligst "+t+" tegn mindre";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Angiv venligst "+t+" tegn mere";return n},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/de.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/de.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/en.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/en.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/es.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/es.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"La carga falló"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/et.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/et.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/eu.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/eu.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/fa.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/fa.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها میتوانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/fi.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/fi.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/fr.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/fr.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/gl.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/gl.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Engada ";return t===1?n+="un carácter":n+=t+" caracteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Elimine ";return t===1?n+="un carácter":n+=t+" caracteres",n},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){var t="Só pode ";return e.maximum===1?t+="un elemento":t+=e.maximum+" elementos",t},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/hi.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/hi.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/hr.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/hr.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/hu.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/hu.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/id.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/id.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/is.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/is.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/it.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/it.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/ko.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/ko.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/lt.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/lt.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%100>9&&e%100<21||e%10===0?e%10>1?n:r:t}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"ių","ius","į"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"ių","ius","į"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ų","us","ą"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/lv.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/lv.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/mk.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/mk.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/nb.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/nb.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn ";return t>1?n+=" flere tegn":n+=" tegn til",n},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/nl.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/nl.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t="Er kunnen maar "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t+=" worden geselecteerd",t},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/pl.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/pl.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maxiumum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/pt-BR.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/pt-BR.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/pt.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/pt.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"carácter",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/ro.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/ro.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să introduceți mai puțin de "+t;return n+=" caracter",n!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți incă "+t;return n+=" caracter",n!==1&&(n+="e"),n},loadingMore:function(){return"Se încarcă…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",t!==1&&(t+="e"),t},noResults:function(){return"Nu a fost găsit nimic"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/ru.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/ru.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/sk.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/sk.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})();
|
||||
3
awx/ui/static/lib/select2/dist/js/i18n/sr.js
vendored
Normal file
3
awx/ui/static/lib/select2/dist/js/i18n/sr.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.0-rc.2 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user