mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 18:09:57 -03:30
Merge branch 'release_3.1.0' into fixJobResults
This commit is contained in:
commit
55e4e9efb6
@ -77,7 +77,7 @@ class FieldLookupBackend(BaseFilterBackend):
|
||||
SUPPORTED_LOOKUPS = ('exact', 'iexact', 'contains', 'icontains',
|
||||
'startswith', 'istartswith', 'endswith', 'iendswith',
|
||||
'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'in',
|
||||
'isnull')
|
||||
'isnull', 'search')
|
||||
|
||||
def get_field_from_lookup(self, model, lookup):
|
||||
field = None
|
||||
@ -148,6 +148,15 @@ class FieldLookupBackend(BaseFilterBackend):
|
||||
re.compile(value)
|
||||
except re.error as e:
|
||||
raise ValueError(e.args[0])
|
||||
elif new_lookup.endswith('__search'):
|
||||
related_model = getattr(field, 'related_model', None)
|
||||
if not related_model:
|
||||
raise ValueError('%s is not searchable' % new_lookup[:-8])
|
||||
new_lookups = []
|
||||
for rm_field in related_model._meta.fields:
|
||||
if rm_field.name in ('username', 'first_name', 'last_name', 'email', 'name', 'description'):
|
||||
new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name))
|
||||
return value, new_lookups
|
||||
else:
|
||||
value = self.value_to_python_for_field(field, value)
|
||||
return value, new_lookup
|
||||
@ -160,6 +169,7 @@ class FieldLookupBackend(BaseFilterBackend):
|
||||
or_filters = []
|
||||
chain_filters = []
|
||||
role_filters = []
|
||||
search_filters = []
|
||||
for key, values in request.query_params.lists():
|
||||
if key in self.RESERVED_NAMES:
|
||||
continue
|
||||
@ -181,6 +191,16 @@ class FieldLookupBackend(BaseFilterBackend):
|
||||
role_filters.append(values[0])
|
||||
continue
|
||||
|
||||
# Search across related objects.
|
||||
if key.endswith('__search'):
|
||||
for value in values:
|
||||
for search_term in force_text(value).replace(',', ' ').split():
|
||||
search_value, new_keys = self.value_to_python(queryset.model, key, search_term)
|
||||
assert isinstance(new_keys, list)
|
||||
for new_key in new_keys:
|
||||
search_filters.append((new_key, search_value))
|
||||
continue
|
||||
|
||||
# Custom chain__ and or__ filters, mutually exclusive (both can
|
||||
# precede not__).
|
||||
q_chain = False
|
||||
@ -211,7 +231,7 @@ class FieldLookupBackend(BaseFilterBackend):
|
||||
and_filters.append((q_not, new_key, value))
|
||||
|
||||
# Now build Q objects for database query filter.
|
||||
if and_filters or or_filters or chain_filters or role_filters:
|
||||
if and_filters or or_filters or chain_filters or role_filters or search_filters:
|
||||
args = []
|
||||
for n, k, v in and_filters:
|
||||
if n:
|
||||
@ -234,6 +254,11 @@ class FieldLookupBackend(BaseFilterBackend):
|
||||
else:
|
||||
q |= Q(**{k:v})
|
||||
args.append(q)
|
||||
if search_filters:
|
||||
q = Q()
|
||||
for k,v in search_filters:
|
||||
q |= Q(**{k:v})
|
||||
args.append(q)
|
||||
for n,k,v in chain_filters:
|
||||
if n:
|
||||
q = ~Q(**{k:v})
|
||||
|
||||
@ -267,10 +267,25 @@ class ListAPIView(generics.ListAPIView, GenericAPIView):
|
||||
fields = []
|
||||
for field in self.model._meta.fields:
|
||||
if field.name in ('username', 'first_name', 'last_name', 'email',
|
||||
'name', 'description', 'email'):
|
||||
'name', 'description'):
|
||||
fields.append(field.name)
|
||||
return fields
|
||||
|
||||
@property
|
||||
def related_search_fields(self):
|
||||
fields = []
|
||||
for field in self.model._meta.fields:
|
||||
if field.name.endswith('_role'):
|
||||
continue
|
||||
if getattr(field, 'related_model', None):
|
||||
fields.append('{}__search'.format(field.name))
|
||||
for rel in self.model._meta.related_objects:
|
||||
name = rel.get_accessor_name()
|
||||
if name.endswith('_set'):
|
||||
continue
|
||||
fields.append('{}__search'.format(name))
|
||||
return fields
|
||||
|
||||
|
||||
class ListCreateAPIView(ListAPIView, generics.ListCreateAPIView):
|
||||
# Base class for a list view that allows creating new objects.
|
||||
|
||||
@ -182,6 +182,10 @@ class Metadata(metadata.SimpleMetadata):
|
||||
if getattr(view, 'search_fields', None):
|
||||
metadata['search_fields'] = view.search_fields
|
||||
|
||||
# Add related search fields if available from the view.
|
||||
if getattr(view, 'related_search_fields', None):
|
||||
metadata['related_search_fields'] = view.related_search_fields
|
||||
|
||||
return metadata
|
||||
|
||||
|
||||
|
||||
@ -56,6 +56,10 @@ within all designated text fields of a model.
|
||||
|
||||
_Added in AWX 1.4_
|
||||
|
||||
(_Added in Ansible Tower 3.1.0_) Search across related fields:
|
||||
|
||||
?related__search=findme
|
||||
|
||||
## Filtering
|
||||
|
||||
Any additional query string parameters may be used to filter the list of
|
||||
|
||||
@ -65,6 +65,9 @@ from awx.api.generics import * # noqa
|
||||
from awx.conf.license import get_license, feature_enabled, feature_exists, LicenseForbids
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.utils import * # noqa
|
||||
from awx.main.utils import (
|
||||
callback_filter_out_ansible_extra_vars
|
||||
)
|
||||
from awx.api.permissions import * # noqa
|
||||
from awx.api.renderers import * # noqa
|
||||
from awx.api.serializers import * # noqa
|
||||
@ -2663,7 +2666,7 @@ class JobTemplateCallback(GenericAPIView):
|
||||
# Send a signal to celery that the job should be started.
|
||||
kv = {"inventory_sources_already_updated": inventory_sources_already_updated}
|
||||
if extra_vars is not None:
|
||||
kv['extra_vars'] = extra_vars
|
||||
kv['extra_vars'] = callback_filter_out_ansible_extra_vars(extra_vars)
|
||||
result = job.signal_start(**kv)
|
||||
if not result:
|
||||
data = dict(msg=_('Error starting job!'))
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Python
|
||||
import contextlib
|
||||
import logging
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
@ -86,6 +87,7 @@ class SettingsWrapper(UserSettingsHolder):
|
||||
self.__dict__['_awx_conf_settings'] = self
|
||||
self.__dict__['_awx_conf_preload_expires'] = None
|
||||
self.__dict__['_awx_conf_preload_lock'] = threading.RLock()
|
||||
self.__dict__['_awx_conf_init_readonly'] = False
|
||||
|
||||
def _get_supported_settings(self):
|
||||
return settings_registry.get_registered_settings()
|
||||
@ -110,6 +112,20 @@ class SettingsWrapper(UserSettingsHolder):
|
||||
return
|
||||
# Otherwise update local preload timeout.
|
||||
self.__dict__['_awx_conf_preload_expires'] = time.time() + SETTING_CACHE_TIMEOUT
|
||||
# Check for any settings that have been defined in Python files and
|
||||
# make those read-only to avoid overriding in the database.
|
||||
if not self._awx_conf_init_readonly and 'migrate_to_database_settings' not in sys.argv:
|
||||
defaults_snapshot = self._get_default('DEFAULTS_SNAPSHOT')
|
||||
for key in self._get_writeable_settings():
|
||||
init_default = defaults_snapshot.get(key, None)
|
||||
try:
|
||||
file_default = self._get_default(key)
|
||||
except AttributeError:
|
||||
file_default = None
|
||||
if file_default != init_default and file_default is not None:
|
||||
logger.warning('Setting %s has been marked read-only!', key)
|
||||
settings_registry._registry[key]['read_only'] = True
|
||||
self.__dict__['_awx_conf_init_readonly'] = True
|
||||
# If local preload timer has expired, check to see if another process
|
||||
# has already preloaded the cache and skip preloading if so.
|
||||
if cache.get('_awx_conf_preload_expires', empty) is not empty:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1253,6 +1253,11 @@ class Command(NoArgsCommand):
|
||||
except re.error:
|
||||
raise CommandError('invalid regular expression for --host-filter')
|
||||
|
||||
'''
|
||||
TODO: Remove this deprecation when we remove support for rax.py
|
||||
'''
|
||||
self.logger.info("Rackspace inventory sync is Deprecated in Tower 3.1.0 and support for Rackspace will be removed in a future release.")
|
||||
|
||||
begin = time.time()
|
||||
self.load_inventory_from_database()
|
||||
|
||||
|
||||
@ -47,6 +47,11 @@ class Migration(migrations.Migration):
|
||||
name='uuid',
|
||||
field=models.CharField(max_length=40),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='credential',
|
||||
name='become_method',
|
||||
field=models.CharField(default=b'', help_text='Privilege escalation method.', max_length=32, blank=True, choices=[(b'', 'None'), (b'sudo', 'Sudo'), (b'su', 'Su'), (b'pbrun', 'Pbrun'), (b'pfexec', 'Pfexec'), (b'dzdo', 'DZDO'), (b'pmrun', 'Pmrun')]),
|
||||
),
|
||||
# Add Workflows
|
||||
migrations.AlterField(
|
||||
model_name='unifiedjob',
|
||||
|
||||
@ -50,6 +50,8 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
('su', _('Su')),
|
||||
('pbrun', _('Pbrun')),
|
||||
('pfexec', _('Pfexec')),
|
||||
('dzdo', _('DZDO')),
|
||||
('pmrun', _('Pmrun')),
|
||||
#('runas', _('Runas')),
|
||||
]
|
||||
|
||||
|
||||
@ -654,6 +654,16 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin):
|
||||
def get_notification_friendly_name(self):
|
||||
return "Job"
|
||||
|
||||
'''
|
||||
Canceling a job also cancels the implicit project update with launch_type
|
||||
run.
|
||||
'''
|
||||
def cancel(self):
|
||||
res = super(Job, self).cancel()
|
||||
if self.project_update:
|
||||
self.project_update.cancel()
|
||||
return res
|
||||
|
||||
|
||||
class JobHostSummary(CreatedModifiedModel):
|
||||
'''
|
||||
|
||||
@ -210,7 +210,7 @@ class AuthToken(BaseModel):
|
||||
REASON_CHOICES = [
|
||||
('', _('Token not invalidated')),
|
||||
('timeout_reached', _('Token is expired')),
|
||||
('limit_reached', _('Maximum per-user sessions reached')),
|
||||
('limit_reached', _('The maximum number of allowed sessions for this user has been exceeded.')),
|
||||
# invalid_token is not a used data-base value, but is returned by the
|
||||
# api when a token is not found
|
||||
('invalid_token', _('Invalid token')),
|
||||
|
||||
@ -366,7 +366,9 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl
|
||||
|
||||
@classmethod
|
||||
def _get_unified_jt_copy_names(cls):
|
||||
return (super(WorkflowJobTemplate, cls)._get_unified_jt_copy_names() +
|
||||
base_list = super(WorkflowJobTemplate, cls)._get_unified_jt_copy_names()
|
||||
base_list.remove('labels')
|
||||
return (base_list +
|
||||
['survey_spec', 'survey_enabled', 'organization'])
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
||||
@ -346,6 +346,7 @@ class TaskManager():
|
||||
'Celery, so it has been marked as failed.',
|
||||
))
|
||||
task_obj.save()
|
||||
_send_notification_templates(task_obj, 'failed')
|
||||
connection.on_commit(lambda: task_obj.websocket_emit_status('failed'))
|
||||
|
||||
logger.error("Task %s appears orphaned... marking as failed" % task)
|
||||
|
||||
@ -109,8 +109,12 @@ def send_notifications(notification_list, job_id=None):
|
||||
raise TypeError("notification_list should be of type list")
|
||||
if job_id is not None:
|
||||
job_actual = UnifiedJob.objects.get(id=job_id)
|
||||
for notification_id in notification_list:
|
||||
notification = Notification.objects.get(id=notification_id)
|
||||
|
||||
notifications = Notification.objects.filter(id__in=notification_list)
|
||||
if job_id is not None:
|
||||
job_actual.notifications.add(*notifications)
|
||||
|
||||
for notification in notifications:
|
||||
try:
|
||||
sent = notification.notification_template.send(notification.subject, notification.body)
|
||||
notification.status = "successful"
|
||||
@ -121,8 +125,6 @@ def send_notifications(notification_list, job_id=None):
|
||||
notification.error = smart_str(e)
|
||||
finally:
|
||||
notification.save()
|
||||
if job_id is not None:
|
||||
job_actual.notifications.add(notification)
|
||||
|
||||
|
||||
@task(bind=True, queue='default')
|
||||
@ -618,7 +620,7 @@ class BaseTask(Task):
|
||||
for child_proc in child_procs:
|
||||
os.kill(child_proc.pid, signal.SIGKILL)
|
||||
os.kill(main_proc.pid, signal.SIGKILL)
|
||||
except TypeError:
|
||||
except (TypeError, psutil.Error):
|
||||
os.kill(job.pid, signal.SIGKILL)
|
||||
else:
|
||||
os.kill(job.pid, signal.SIGTERM)
|
||||
@ -708,6 +710,11 @@ class BaseTask(Task):
|
||||
stdout_handle.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
instance = self.update_model(pk)
|
||||
if instance.cancel_flag:
|
||||
status = 'canceled'
|
||||
|
||||
instance = self.update_model(pk, status=status, result_traceback=tb,
|
||||
output_replacements=output_replacements,
|
||||
**extra_update_fields)
|
||||
@ -809,7 +816,7 @@ class RunJob(BaseTask):
|
||||
env['REST_API_URL'] = settings.INTERNAL_API_URL
|
||||
env['REST_API_TOKEN'] = job.task_auth_token or ''
|
||||
env['TOWER_HOST'] = settings.TOWER_URL_BASE
|
||||
env['MAX_EVENT_RES'] = settings.MAX_EVENT_RES_DATA
|
||||
env['MAX_EVENT_RES'] = str(settings.MAX_EVENT_RES_DATA)
|
||||
env['CALLBACK_QUEUE'] = settings.CALLBACK_QUEUE
|
||||
env['CALLBACK_CONNECTION'] = settings.BROKER_URL
|
||||
if getattr(settings, 'JOB_CALLBACK_DEBUG', False):
|
||||
@ -1045,17 +1052,18 @@ class RunJob(BaseTask):
|
||||
local_project_sync = job.project.create_project_update(launch_type="sync")
|
||||
local_project_sync.job_type = 'run'
|
||||
local_project_sync.save()
|
||||
# save the associated project update before calling run() so that a
|
||||
# cancel() call on the job can cancel the project update
|
||||
job = self.update_model(job.pk, project_update=local_project_sync)
|
||||
|
||||
project_update_task = local_project_sync._get_task_class()
|
||||
try:
|
||||
project_update_task().run(local_project_sync.id)
|
||||
job.scm_revision = job.project.scm_revision
|
||||
job.project_update = local_project_sync
|
||||
job.save()
|
||||
job = self.update_model(job.pk, scm_revision=job.project.scm_revision)
|
||||
except Exception:
|
||||
job.status = 'failed'
|
||||
job.job_explanation = 'Previous Task Failed: {"job_type": "%s", "job_name": "%s", "job_id": "%s"}' % \
|
||||
('project_update', local_project_sync.name, local_project_sync.id)
|
||||
job.save()
|
||||
job = self.update_model(job.pk, status='failed',
|
||||
job_explanation=('Previous Task Failed: {"job_type": "%s", "job_name": "%s", "job_id": "%s"}' %
|
||||
('project_update', local_project_sync.name, local_project_sync.id)))
|
||||
raise
|
||||
|
||||
def post_run_hook(self, job, status, **kwargs):
|
||||
@ -1737,6 +1745,10 @@ class RunAdHocCommand(BaseTask):
|
||||
d[re.compile(r'^pfexec password.*:\s*?$', re.M)] = 'become_password'
|
||||
d[re.compile(r'^RUNAS password.*:\s*?$', re.M)] = 'become_password'
|
||||
d[re.compile(r'^runas password.*:\s*?$', re.M)] = 'become_password'
|
||||
d[re.compile(r'^DZDO password.*:\s*?$', re.M)] = 'become_password'
|
||||
d[re.compile(r'^dzdo password.*:\s*?$', re.M)] = 'become_password'
|
||||
d[re.compile(r'^PMRUN password.*:\s*?$', re.M)] = 'become_password'
|
||||
d[re.compile(r'^pmrun password.*:\s*?$', re.M)] = 'become_password'
|
||||
d[re.compile(r'^SSH password:\s*?$', re.M)] = 'ssh_password'
|
||||
d[re.compile(r'^Password:\s*?$', re.M)] = 'ssh_password'
|
||||
return d
|
||||
|
||||
@ -77,7 +77,7 @@ def test_net_cred_ssh_agent(mocker, get_ssh_version):
|
||||
mocker.patch.object(run_job, 'post_run_hook', return_value=None)
|
||||
|
||||
run_job.run(mock_job.id)
|
||||
assert run_job.update_model.call_count == 3
|
||||
assert run_job.update_model.call_count == 4
|
||||
|
||||
job_args = run_job.update_model.call_args_list[1][1].get('job_args')
|
||||
assert 'ssh-add' in job_args
|
||||
|
||||
@ -38,17 +38,17 @@ def test_send_notifications_list(mocker):
|
||||
mock_job = mocker.MagicMock(spec=UnifiedJob)
|
||||
patches.append(mocker.patch('awx.main.models.UnifiedJob.objects.get', return_value=mock_job))
|
||||
|
||||
mock_notification = mocker.MagicMock(spec=Notification, subject="test", body={'hello': 'world'})
|
||||
patches.append(mocker.patch('awx.main.models.Notification.objects.get', return_value=mock_notification))
|
||||
mock_notifications = [mocker.MagicMock(spec=Notification, subject="test", body={'hello': 'world'})]
|
||||
patches.append(mocker.patch('awx.main.models.Notification.objects.filter', return_value=mock_notifications))
|
||||
|
||||
with apply_patches(patches):
|
||||
send_notifications([1,2], job_id=1)
|
||||
assert Notification.objects.get.call_count == 2
|
||||
assert mock_notification.status == "successful"
|
||||
assert mock_notification.save.called
|
||||
assert Notification.objects.filter.call_count == 1
|
||||
assert mock_notifications[0].status == "successful"
|
||||
assert mock_notifications[0].save.called
|
||||
|
||||
assert mock_job.notifications.add.called
|
||||
assert mock_job.notifications.add.called_with(mock_notification)
|
||||
assert mock_job.notifications.add.called_with(*mock_notifications)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("current_instances,call_count", [(91, 2), (89,1)])
|
||||
|
||||
@ -43,7 +43,8 @@ __all__ = ['get_object_or_400', 'get_object_or_403', 'camelcase_to_underscore',
|
||||
'copy_m2m_relationships' ,'cache_list_capabilities', 'to_python_boolean',
|
||||
'ignore_inventory_computed_fields', 'ignore_inventory_group_removal',
|
||||
'_inventory_updates', 'get_pk_from_dict', 'getattrd', 'NoDefaultProvided',
|
||||
'get_current_apps', 'set_current_apps', 'OutputEventFilter']
|
||||
'get_current_apps', 'set_current_apps', 'OutputEventFilter',
|
||||
'callback_filter_out_ansible_extra_vars',]
|
||||
|
||||
|
||||
def get_object_or_400(klass, *args, **kwargs):
|
||||
@ -824,3 +825,12 @@ class OutputEventFilter(object):
|
||||
self._current_event_data = next_event_data
|
||||
else:
|
||||
self._current_event_data = None
|
||||
|
||||
|
||||
def callback_filter_out_ansible_extra_vars(extra_vars):
|
||||
extra_vars_redacted = {}
|
||||
for key, value in extra_vars.iteritems():
|
||||
if not key.startswith('ansible_'):
|
||||
extra_vars_redacted[key] = value
|
||||
return extra_vars_redacted
|
||||
|
||||
|
||||
@ -22,19 +22,19 @@ EXAMPLES = '''
|
||||
# {
|
||||
# "source": "apt",
|
||||
# "version": "1.0.6-5",
|
||||
# "architecture": "amd64",
|
||||
# "arch": "amd64",
|
||||
# "name": "libbz2-1.0"
|
||||
# },
|
||||
# {
|
||||
# "source": "apt",
|
||||
# "version": "2.7.1-4ubuntu1",
|
||||
# "architecture": "amd64",
|
||||
# "arch": "amd64",
|
||||
# "name": "patch"
|
||||
# },
|
||||
# {
|
||||
# "source": "apt",
|
||||
# "version": "4.8.2-19ubuntu1",
|
||||
# "architecture": "amd64",
|
||||
# "arch": "amd64",
|
||||
# "name": "gcc-4.8-base"
|
||||
# }, ... ] } }
|
||||
'''
|
||||
@ -64,7 +64,7 @@ def deb_package_list():
|
||||
ac_pkg = apt_cache[package].installed
|
||||
package_details = dict(name=package,
|
||||
version=ac_pkg.version,
|
||||
architecture=ac_pkg.architecture,
|
||||
arch=ac_pkg.architecture,
|
||||
source='apt')
|
||||
installed_packages.append(package_details)
|
||||
return installed_packages
|
||||
|
||||
@ -82,14 +82,13 @@ PASSWORD_HASHERS = (
|
||||
# Configure a default UUID for development only.
|
||||
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
|
||||
|
||||
# Store a snapshot of default settings at this point (only for migrating from
|
||||
# file to database settings).
|
||||
if 'migrate_to_database_settings' in sys.argv:
|
||||
DEFAULTS_SNAPSHOT = {}
|
||||
this_module = sys.modules[__name__]
|
||||
for setting in dir(this_module):
|
||||
if setting == setting.upper():
|
||||
DEFAULTS_SNAPSHOT[setting] = copy.deepcopy(getattr(this_module, setting))
|
||||
# Store a snapshot of default settings at this point before loading any
|
||||
# customizable config files.
|
||||
DEFAULTS_SNAPSHOT = {}
|
||||
this_module = sys.modules[__name__]
|
||||
for setting in dir(this_module):
|
||||
if setting == setting.upper():
|
||||
DEFAULTS_SNAPSHOT[setting] = copy.deepcopy(getattr(this_module, setting))
|
||||
|
||||
# If there is an `/etc/tower/settings.py`, include it.
|
||||
# If there is a `/etc/tower/conf.d/*.py`, include them.
|
||||
|
||||
@ -57,14 +57,13 @@ LOGGING['handlers']['fact_receiver']['filename'] = '/var/log/tower/fact_receiver
|
||||
LOGGING['handlers']['system_tracking_migrations']['filename'] = '/var/log/tower/tower_system_tracking_migrations.log'
|
||||
LOGGING['handlers']['rbac_migrations']['filename'] = '/var/log/tower/tower_rbac_migrations.log'
|
||||
|
||||
# Store a snapshot of default settings at this point (only for migrating from
|
||||
# file to database settings).
|
||||
if 'migrate_to_database_settings' in sys.argv:
|
||||
DEFAULTS_SNAPSHOT = {}
|
||||
this_module = sys.modules[__name__]
|
||||
for setting in dir(this_module):
|
||||
if setting == setting.upper():
|
||||
DEFAULTS_SNAPSHOT[setting] = copy.deepcopy(getattr(this_module, setting))
|
||||
# Store a snapshot of default settings at this point before loading any
|
||||
# customizable config files.
|
||||
DEFAULTS_SNAPSHOT = {}
|
||||
this_module = sys.modules[__name__]
|
||||
for setting in dir(this_module):
|
||||
if setting == setting.upper():
|
||||
DEFAULTS_SNAPSHOT[setting] = copy.deepcopy(getattr(this_module, setting))
|
||||
|
||||
# Load settings from any .py files in the global conf.d directory specified in
|
||||
# the environment, defaulting to /etc/tower/conf.d/.
|
||||
|
||||
@ -20,15 +20,13 @@ export default ['templateUrl', function(templateUrl) {
|
||||
{label: 'Hosts', value: 'host'},
|
||||
{label: 'Inventories', value: 'inventory'},
|
||||
{label: 'Inventory Scripts', value: 'inventory_script'},
|
||||
{label: 'Job Templates', value: 'job_template'},
|
||||
{label: 'Jobs', value: 'job'},
|
||||
{label: 'Organizations', value: 'organization'},
|
||||
{label: 'Projects', value: 'project'},
|
||||
{label: 'Schedules', value: 'schedule'},
|
||||
{label: 'Teams', value: 'team'},
|
||||
{label: 'Templates', value: 'template'},
|
||||
{label: 'Users', value: 'user'},
|
||||
{label: 'Workflow Job Templates', value: 'workflow_job_template'}
|
||||
{label: 'Users', value: 'user'}
|
||||
];
|
||||
|
||||
CreateSelect2({
|
||||
|
||||
@ -36,6 +36,35 @@ export function CredentialsList($scope, $rootScope, $location, $log,
|
||||
$scope.selected = [];
|
||||
}
|
||||
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
);
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.kind && $scope.options &&
|
||||
$scope.options.hasOwnProperty('kind')) {
|
||||
$scope.options.kind.choices.every(function(choice) {
|
||||
if (choice[0] === item.kind) {
|
||||
itm.kind_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.addCredential = function() {
|
||||
$state.go('credentials.add');
|
||||
};
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
|
||||
export function JobsListController($state, $rootScope, $log, $scope, $compile, $stateParams,
|
||||
ClearScope, Find, DeleteJob, RelaunchJob, AllJobsList, ScheduledJobsList, GetBasePath, Dataset, GetChoices) {
|
||||
ClearScope, Find, DeleteJob, RelaunchJob, AllJobsList, ScheduledJobsList, GetBasePath, Dataset) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
@ -28,40 +28,44 @@ export function JobsListController($state, $rootScope, $log, $scope, $compile, $
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
$scope.showJobType = true;
|
||||
}
|
||||
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
_.forEach($scope[list.name], buildTooltips);
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
if(item.summary_fields && item.summary_fields.source_workflow_job &&
|
||||
item.summary_fields.source_workflow_job.id){
|
||||
item.workflow_result_link = `/#/workflows/${item.summary_fields.source_workflow_job.id}`;
|
||||
}
|
||||
// Set the item type label
|
||||
if (list.fields.type) {
|
||||
$scope.type_choices.every(function(choice) {
|
||||
if (choice.value === item.type) {
|
||||
itm.type_label = choice.label;
|
||||
);
|
||||
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
if(item.summary_fields && item.summary_fields.source_workflow_job &&
|
||||
item.summary_fields.source_workflow_job.id){
|
||||
item.workflow_result_link = `/#/workflows/${item.summary_fields.source_workflow_job.id}`;
|
||||
}
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.type && $scope.options &&
|
||||
$scope.options.hasOwnProperty('type')) {
|
||||
$scope.options.type.choices.every(function(choice) {
|
||||
if (choice[0] === item.type) {
|
||||
itm.type_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: GetBasePath('unified_jobs'),
|
||||
field: 'type',
|
||||
variable: 'type_choices',
|
||||
callback: 'choicesReady'
|
||||
buildTooltips(itm);
|
||||
});
|
||||
}
|
||||
|
||||
function buildTooltips(job) {
|
||||
job.status_tip = 'Job ' + job.status + ". Click for details.";
|
||||
}
|
||||
@ -131,5 +135,5 @@ export function JobsListController($state, $rootScope, $log, $scope, $compile, $
|
||||
}
|
||||
|
||||
JobsListController.$inject = ['$state', '$rootScope', '$log', '$scope', '$compile', '$stateParams',
|
||||
'ClearScope', 'Find', 'DeleteJob', 'RelaunchJob', 'AllJobsList', 'ScheduledJobsList', 'GetBasePath', 'Dataset', 'GetChoices'
|
||||
'ClearScope', 'Find', 'DeleteJob', 'RelaunchJob', 'AllJobsList', 'ScheduledJobsList', 'GetBasePath', 'Dataset'
|
||||
];
|
||||
|
||||
@ -38,10 +38,39 @@ export function ProjectsList($scope, $rootScope, $location, $log, $stateParams,
|
||||
$rootScope.flashMessage = null;
|
||||
}
|
||||
|
||||
$scope.$watch(`${list.name}`, function() {
|
||||
_.forEach($scope[list.name], buildTooltips);
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
);
|
||||
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.scm_type && $scope.options &&
|
||||
$scope.options.hasOwnProperty('scm_type')) {
|
||||
$scope.options.scm_type.choices.every(function(choice) {
|
||||
if (choice[0] === item.scm_type) {
|
||||
itm.type_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
buildTooltips(itm);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function buildTooltips(project) {
|
||||
project.statusIcon = GetProjectIcon(project.status);
|
||||
project.statusTip = GetProjectToolTip(project.status);
|
||||
|
||||
@ -217,6 +217,7 @@ export function TeamsEdit($scope, $rootScope, $stateParams,
|
||||
$rootScope.flashMessage = null;
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
var data = processNewData(form.fields);
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(data).success(function() {
|
||||
$state.go($state.current, null, { reload: true });
|
||||
})
|
||||
|
||||
@ -311,7 +311,7 @@ export function UsersEdit($scope, $rootScope, $location,
|
||||
$scope.formSave = function() {
|
||||
$rootScope.flashMessage = null;
|
||||
if ($scope[form.name + '_form'].$valid) {
|
||||
Rest.setUrl(defaultUrl + id + '/');
|
||||
Rest.setUrl(defaultUrl + '/');
|
||||
var data = processNewData(form.fields);
|
||||
Rest.put(data).success(function() {
|
||||
$state.go($state.current, null, { reload: true });
|
||||
|
||||
@ -47,7 +47,7 @@ export default
|
||||
};
|
||||
|
||||
scope.editJobTemplate = function (jobTemplateId) {
|
||||
$state.go('templates.editJobTemplate', {id: jobTemplateId});
|
||||
$state.go('templates.editJobTemplate', {job_template_id: jobTemplateId});
|
||||
};
|
||||
}
|
||||
}];
|
||||
|
||||
@ -263,7 +263,7 @@ export default
|
||||
"ssh_key_unlock": {
|
||||
label: i18n._('Private Key Passphrase'),
|
||||
type: 'sensitive',
|
||||
ngShow: "kind.value == 'ssh' || kind.value == 'scm'",
|
||||
ngShow: "kind.value === 'ssh' || kind.value === 'scm' || kind.value === 'net'",
|
||||
ngDisabled: "keyEntered === false || ssh_key_unlock_ask || !(credential_obj.summary_fields.user_capabilities.edit || canAdd)",
|
||||
subCheckbox: {
|
||||
variable: 'ssh_key_unlock_ask',
|
||||
|
||||
@ -307,6 +307,17 @@ export default
|
||||
dataContainer: "body",
|
||||
labelClass: 'stack-inline',
|
||||
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
|
||||
}, {
|
||||
name: 'allow_simultaneous',
|
||||
label: i18n._('Enable Concurrent Jobs'),
|
||||
type: 'checkbox',
|
||||
column: 2,
|
||||
awPopOver: "<p>" + i18n._("If enabled, simultaneous runs of this job template will be allowed.") + "</p>",
|
||||
dataPlacement: 'right',
|
||||
dataTitle: i18n._('Enable Concurrent Jobs'),
|
||||
dataContainer: "body",
|
||||
labelClass: 'stack-inline',
|
||||
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
|
||||
}]
|
||||
},
|
||||
callback_url: {
|
||||
|
||||
@ -185,7 +185,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
||||
type: 'number',
|
||||
integer: true,
|
||||
min: 0,
|
||||
ngShow: "scm_update_on_launch && projectSelected && scm_type.value !== 'manual'",
|
||||
ngShow: "scm_update_on_launch && scm_type.value !== 'manual'",
|
||||
spinner: true,
|
||||
"default": '0',
|
||||
awPopOver: '<p>' + i18n._('Time in seconds to consider a project to be current. During job runs and callbacks the task system will ' +
|
||||
|
||||
@ -25,9 +25,6 @@ export default
|
||||
case 'inventory':
|
||||
rtnTitle = 'INVENTORIES';
|
||||
break;
|
||||
case 'job_template':
|
||||
rtnTitle = 'JOB TEMPLATES';
|
||||
break;
|
||||
case 'credential':
|
||||
rtnTitle = 'CREDENTIALS';
|
||||
break;
|
||||
@ -55,9 +52,6 @@ export default
|
||||
case 'template':
|
||||
rtnTitle = 'TEMPLATES';
|
||||
break;
|
||||
case 'workflow_job_template':
|
||||
rtnTitle = 'WORKFLOW JOB TEMPLATES';
|
||||
break;
|
||||
}
|
||||
|
||||
return rtnTitle;
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
['$scope', '$state', '$stateParams', 'generateList', 'GroupManageService', 'GetBasePath', 'CopyMoveGroupList', 'group',
|
||||
function($scope, $state, $stateParams, GenerateList, GroupManageService, GetBasePath, CopyMoveGroupList, group){
|
||||
var list = CopyMoveGroupList,
|
||||
view = GenerateList;
|
||||
['$scope', '$state', '$stateParams', 'GroupManageService', 'GetBasePath', 'CopyMoveGroupList', 'group', 'Dataset',
|
||||
function($scope, $state, $stateParams, GroupManageService, GetBasePath, CopyMoveGroupList, group, Dataset){
|
||||
var list = CopyMoveGroupList;
|
||||
|
||||
$scope.item = group;
|
||||
$scope.submitMode = $stateParams.groups === undefined ? 'move' : 'copy';
|
||||
$scope['toggle_'+ list.iterator] = function(id){
|
||||
@ -58,33 +58,18 @@
|
||||
$(el).prop('disabled', (idx, value) => !value);
|
||||
});
|
||||
};
|
||||
var init = function(){
|
||||
var url = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
|
||||
url += $stateParams.group ? '?not__id__in=' + group.id + ',' + _.last($stateParams.group) : '?not__id=' + group.id;
|
||||
list.basePath = url;
|
||||
$scope.atRootLevel = $stateParams.group ? false : true;
|
||||
view.inject(list, {
|
||||
mode: 'lookup',
|
||||
id: 'copyMove-list',
|
||||
scope: $scope,
|
||||
input_type: 'radio'
|
||||
});
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// SearchInit({
|
||||
// scope: $scope,
|
||||
// set: list.name,
|
||||
// list: list,
|
||||
// url: url
|
||||
// });
|
||||
// PaginateInit({
|
||||
// scope: $scope,
|
||||
// list: list,
|
||||
// url : url,
|
||||
// mode: 'lookup'
|
||||
// });
|
||||
// $scope.search(list.iterator, null, true, false);
|
||||
// remove the current group from list
|
||||
};
|
||||
function init(){
|
||||
var url = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
|
||||
url += $stateParams.group ? '?not__id__in=' + group.id + ',' + _.last($stateParams.group) : '?not__id=' + group.id;
|
||||
list.basePath = url;
|
||||
$scope.atRootLevel = $stateParams.group ? false : true;
|
||||
|
||||
// search init
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
}
|
||||
|
||||
init();
|
||||
}];
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
['$scope', '$state', '$stateParams', 'generateList', 'HostManageService', 'GetBasePath', 'CopyMoveGroupList', 'host',
|
||||
function($scope, $state, $stateParams, GenerateList, HostManageService, GetBasePath, CopyMoveGroupList, host){
|
||||
var list = CopyMoveGroupList,
|
||||
view = GenerateList;
|
||||
['$scope', '$state', '$stateParams', 'generateList', 'HostManageService', 'GetBasePath', 'CopyMoveGroupList', 'host', 'Dataset',
|
||||
function($scope, $state, $stateParams, GenerateList, HostManageService, GetBasePath, CopyMoveGroupList, host, Dataset){
|
||||
var list = CopyMoveGroupList;
|
||||
|
||||
$scope.item = host;
|
||||
$scope.submitMode = 'copy';
|
||||
$scope['toggle_'+ list.iterator] = function(id){
|
||||
@ -40,29 +40,11 @@
|
||||
}
|
||||
};
|
||||
var init = function(){
|
||||
var url = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
|
||||
list.basePath = url;
|
||||
view.inject(list, {
|
||||
mode: 'lookup',
|
||||
id: 'copyMove-list',
|
||||
scope: $scope,
|
||||
input_type: 'radio'
|
||||
});
|
||||
// search init
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// SearchInit({
|
||||
// scope: $scope,
|
||||
// set: list.name,
|
||||
// list: list,
|
||||
// url: url
|
||||
// });
|
||||
// PaginateInit({
|
||||
// scope: $scope,
|
||||
// list: list,
|
||||
// url : url,
|
||||
// mode: 'lookup'
|
||||
// });
|
||||
// $scope.search(list.iterator, null, true, false);
|
||||
};
|
||||
init();
|
||||
}];
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<input type="radio" ng-model="submitMode" value="move" class="ng-pristine ng-untouched ng-valid"> Move
|
||||
</label>
|
||||
</div>
|
||||
<div id="copyMove-list"></div>
|
||||
<div id="copyMove-list" ui-view="copyMoveList"></div>
|
||||
<div class="copyMove-root form-group pull-left" ng-hide="atRootLevel">
|
||||
<span><input type="checkbox" ng-model="targetRootGroup" ng-change="toggleTargetRootGroup()"> Use the inventory root</span>
|
||||
</div>
|
||||
|
||||
@ -10,14 +10,31 @@ import CopyMoveHostsController from './copy-move-hosts.controller';
|
||||
|
||||
var copyMoveGroupRoute = {
|
||||
name: 'inventoryManage.copyMoveGroup',
|
||||
url: '/copy-move-group/{group_id}',
|
||||
url: '/copy-move-group/{group_id:int}',
|
||||
searchPrefix: 'copy',
|
||||
data: {
|
||||
group_id: 'group_id',
|
||||
},
|
||||
params: {
|
||||
copy_search: {
|
||||
value: {
|
||||
not__id__in: null
|
||||
},
|
||||
dynamic: true,
|
||||
squash: ''
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: "COPY OR MOVE {{item.name}}"
|
||||
},
|
||||
resolve: {
|
||||
Dataset: ['CopyMoveGroupList', 'QuerySet', '$stateParams', 'GetBasePath', 'group',
|
||||
function(list, qs, $stateParams, GetBasePath, group) {
|
||||
$stateParams.copy_search.not__id__in = ($stateParams.group.length > 0 ? group.id + ',' + _.last($stateParams.group) : group.id);
|
||||
let path = GetBasePath(list.name);
|
||||
return qs.search(path, $stateParams.copy_search);
|
||||
}
|
||||
],
|
||||
group: ['GroupManageService', '$stateParams', function(GroupManageService, $stateParams){
|
||||
return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]);
|
||||
}]
|
||||
@ -26,16 +43,33 @@ var copyMoveGroupRoute = {
|
||||
'form@inventoryManage' : {
|
||||
controller: CopyMoveGroupsController,
|
||||
templateUrl: templateUrl('inventories/manage/copy-move/copy-move'),
|
||||
},
|
||||
'copyMoveList@inventoryManage.copyMoveGroup': {
|
||||
templateProvider: function(CopyMoveGroupList, generateList) {
|
||||
let html = generateList.build({
|
||||
list: CopyMoveGroupList,
|
||||
mode: 'lookup',
|
||||
input_type: 'radio'
|
||||
});
|
||||
return html;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var copyMoveHostRoute = {
|
||||
name: 'inventoryManage.copyMoveHost',
|
||||
url: '/copy-move-host/{host_id}',
|
||||
searchPrefix: 'copy',
|
||||
ncyBreadcrumb: {
|
||||
label: "COPY OR MOVE {{item.name}}"
|
||||
},
|
||||
resolve: {
|
||||
Dataset: ['CopyMoveGroupList', 'QuerySet', '$stateParams', 'GetBasePath',
|
||||
function(list, qs, $stateParams, GetBasePath) {
|
||||
let path = GetBasePath(list.name);
|
||||
return qs.search(path, $stateParams.copy_search);
|
||||
}
|
||||
],
|
||||
host: ['HostManageService', '$stateParams', function(HostManageService, $stateParams){
|
||||
return HostManageService.get({id: $stateParams.host_id}).then(res => res.data.results[0]);
|
||||
}]
|
||||
@ -44,6 +78,16 @@ var copyMoveHostRoute = {
|
||||
'form@inventoryManage': {
|
||||
templateUrl: templateUrl('inventories/manage/copy-move/copy-move'),
|
||||
controller: CopyMoveHostsController,
|
||||
},
|
||||
'copyMoveList@inventoryManage.copyMoveHost': {
|
||||
templateProvider: function(CopyMoveGroupList, generateList) {
|
||||
let html = generateList.build({
|
||||
list: CopyMoveGroupList,
|
||||
mode: 'lookup',
|
||||
input_type: 'radio'
|
||||
});
|
||||
return html;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -176,3 +176,27 @@ job-results-standard-out {
|
||||
flex: 1;
|
||||
display: flex
|
||||
}
|
||||
|
||||
.JobResults-extraVarsHelp {
|
||||
margin-left: 10px;
|
||||
color: @default-icon;
|
||||
}
|
||||
|
||||
.JobResults .CodeMirror.cm-s-default,
|
||||
.JobResults .CodeMirror-line {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.JobResults .CodeMirror-gutter.CodeMirror-lint-markers,
|
||||
.JobResults .CodeMirror-gutter.CodeMirror-linenumbers {
|
||||
background-color: #ebebeb;
|
||||
color: @b7grey;
|
||||
}
|
||||
|
||||
.JobResults .CodeMirror-lines {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.JobResults .CodeMirror-cursors {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -353,6 +353,10 @@
|
||||
<label class="JobResults-resultRowLabel
|
||||
JobResults-resultRowLabel--fullWidth">
|
||||
Extra Variables
|
||||
<i class="JobResults-extraVarsHelp fa fa-question-circle"
|
||||
aw-tool-tip="Read only view of extra variables added to the job template."
|
||||
data-placement="top">
|
||||
</i>
|
||||
</label>
|
||||
<textarea
|
||||
rows="6"
|
||||
@ -414,6 +418,7 @@
|
||||
<div class="StandardOut-panelHeaderText">
|
||||
<i class="JobResults-statusResultIcon
|
||||
fa icon-job-{{ job_status }}"
|
||||
ng-show="stdoutFullScreen"
|
||||
aw-tool-tip="Job {{status_label}}"
|
||||
data-tip-watch="status_tooltip"
|
||||
aw-tip-placement="top"
|
||||
|
||||
@ -86,7 +86,7 @@ export default
|
||||
columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',
|
||||
"view": {
|
||||
mode: "all",
|
||||
ngClick: "viewJob(job.id)",
|
||||
ngClick: "viewJobDetails(job)",
|
||||
awToolTip: "View the job",
|
||||
dataPlacement: "top"
|
||||
},
|
||||
|
||||
@ -37,6 +37,7 @@ export default
|
||||
},
|
||||
kind: {
|
||||
label: i18n._('Type'),
|
||||
ngBind: 'credential.kind_label',
|
||||
excludeModal: true,
|
||||
nosort: true,
|
||||
columnClass: 'col-md-2 hidden-sm hidden-xs'
|
||||
|
||||
@ -12,7 +12,7 @@ export default
|
||||
.value('CopyMoveGroupList', {
|
||||
|
||||
name: 'groups',
|
||||
iterator: 'group',
|
||||
iterator: 'copy',
|
||||
selectTitle: 'Copy Groups',
|
||||
index: false,
|
||||
well: false,
|
||||
|
||||
@ -30,7 +30,8 @@ export default
|
||||
dataPlacement: 'right',
|
||||
icon: "icon-job-{{ project.statusIcon }}",
|
||||
columnClass: "List-staticColumn--smallStatus",
|
||||
nosort: true
|
||||
nosort: true,
|
||||
excludeModal: true
|
||||
},
|
||||
name: {
|
||||
key: true,
|
||||
@ -46,6 +47,7 @@ export default
|
||||
},
|
||||
scm_type: {
|
||||
label: i18n._('Type'),
|
||||
ngBind: 'project.type_label',
|
||||
excludeModal: true,
|
||||
columnClass: 'col-lg-3 col-md-2 col-sm-3 hidden-xs'
|
||||
},
|
||||
|
||||
@ -31,8 +31,7 @@ export default
|
||||
name: {
|
||||
label: i18n._('Name'),
|
||||
columnClass: 'col-lg-4 col-md-5 col-sm-5 col-xs-7 List-staticColumnAdjacent',
|
||||
sourceModel: 'unified_job_template',
|
||||
sourceField: 'name',
|
||||
ngBind: 'schedule.summary_fields.unified_job_template.name',
|
||||
ngClick: "editSchedule(schedule)",
|
||||
awToolTip: "{{ schedule.nameTip | sanitize}}",
|
||||
dataTipWatch: 'schedule.nameTip',
|
||||
|
||||
@ -5,55 +5,33 @@
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
[ '$rootScope','Wait', 'generateList', 'NotificationsList',
|
||||
'GetBasePath' , 'Rest' ,
|
||||
'ProcessErrors', 'Prompt', '$state', 'GetChoices', 'Empty', 'Find',
|
||||
'ngToast', '$compile', '$filter','ToggleNotification',
|
||||
'NotificationsListInit', '$stateParams', 'management_job',
|
||||
[ 'NotificationsList', 'GetBasePath', 'ToggleNotification', 'NotificationsListInit',
|
||||
'$stateParams', 'Dataset', '$scope',
|
||||
function(
|
||||
$rootScope,Wait, GenerateList, NotificationsList,
|
||||
GetBasePath, Rest,
|
||||
ProcessErrors, Prompt, $state, GetChoices, Empty, Find, ngToast,
|
||||
$compile, $filter, ToggleNotification, NotificationsListInit,
|
||||
$stateParams, management_job) {
|
||||
var scope = $rootScope.$new(),
|
||||
url = GetBasePath('notification_templates'),
|
||||
defaultUrl = GetBasePath('system_job_templates'),
|
||||
list,
|
||||
view = GenerateList,
|
||||
NotificationsList, GetBasePath, ToggleNotification, NotificationsListInit,
|
||||
$stateParams, Dataset, $scope) {
|
||||
var defaultUrl = GetBasePath('system_job_templates'),
|
||||
list = NotificationsList,
|
||||
id = $stateParams.management_id;
|
||||
|
||||
list = _.cloneDeep(NotificationsList);
|
||||
delete list.actions.add;
|
||||
list.listTitle = `${management_job.name} <div class="List-titleLockup"></div> Notifications`;
|
||||
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
|
||||
list.searchRowActions = {
|
||||
add: {
|
||||
label: 'Add Notification',
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addNotificationTemplate()',
|
||||
awToolTip: 'Create a new notification template',
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
buttonContent: '+ ADD NOTIFICATION TEMPLATE'
|
||||
}
|
||||
};
|
||||
view.inject( list, {
|
||||
mode: 'edit',
|
||||
cancelButton: true,
|
||||
scope: scope
|
||||
});
|
||||
function init() {
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
NotificationsListInit({
|
||||
scope: scope,
|
||||
url: defaultUrl,
|
||||
id: id
|
||||
});
|
||||
NotificationsListInit({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
id: id
|
||||
});
|
||||
|
||||
scope.formCancel = function() {
|
||||
$state.go('managementJobsList');
|
||||
};
|
||||
$scope.$watch(`${list.iterator}_dataset`, function() {
|
||||
// The list data has changed and we need to update which notifications are on/off
|
||||
$scope.$emit('relatednotifications');
|
||||
});
|
||||
}
|
||||
|
||||
scope.toggleNotification = function(event, notifier_id, column) {
|
||||
$scope.toggleNotification = function(event, notifier_id, column) {
|
||||
var notifier = this.notification;
|
||||
try {
|
||||
$(event.target).tooltip('hide');
|
||||
@ -62,60 +40,15 @@ export default
|
||||
// ignore
|
||||
}
|
||||
ToggleNotification({
|
||||
scope: scope,
|
||||
url: defaultUrl,
|
||||
id: id,
|
||||
scope: $scope,
|
||||
url: defaultUrl + id,
|
||||
notifier: notifier,
|
||||
column: column,
|
||||
callback: 'NotificationRefresh'
|
||||
});
|
||||
};
|
||||
|
||||
if (scope.removePostRefresh) {
|
||||
scope.removePostRefresh();
|
||||
}
|
||||
scope.removePostRefresh = scope.$on('PostRefresh', function () {
|
||||
scope.$emit('relatednotifications');
|
||||
});
|
||||
|
||||
if (scope.removeChoicesHere) {
|
||||
scope.removeChoicesHere();
|
||||
}
|
||||
scope.removeChoicesHere = scope.$on('choicesReadyNotifierList', function () {
|
||||
list.fields.notification_type.searchOptions = scope.notification_type_options;
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// SearchInit({
|
||||
// scope: scope,
|
||||
// set: 'notifications',
|
||||
// list: list,
|
||||
// url: url
|
||||
// });
|
||||
|
||||
if ($rootScope.addedItem) {
|
||||
scope.addedItem = $rootScope.addedItem;
|
||||
delete $rootScope.addedItem;
|
||||
}
|
||||
|
||||
// @issue: OLD SEARCH
|
||||
// PaginateInit({
|
||||
// scope: scope,
|
||||
// list: list,
|
||||
// url: url
|
||||
// });
|
||||
//
|
||||
// scope.search(list.iterator);
|
||||
|
||||
});
|
||||
|
||||
GetChoices({
|
||||
scope: scope,
|
||||
url: url,
|
||||
field: 'notification_type',
|
||||
variable: 'notification_type_options',
|
||||
callback: 'choicesReadyNotifierList'
|
||||
});
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
];
|
||||
|
||||
@ -4,43 +4,40 @@
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import {templateUrl} from '../../shared/template-url/template-url.factory';
|
||||
|
||||
export default {
|
||||
name: 'managementJobsList.notifications',
|
||||
route: '/:management_id/notifications',
|
||||
templateUrl: templateUrl('management-jobs/notifications/notifications'),
|
||||
controller: 'managementJobsNotificationsController',
|
||||
params: {card: null},
|
||||
resolve: {
|
||||
management_job:
|
||||
[ '$stateParams',
|
||||
'$q',
|
||||
'Rest',
|
||||
'GetBasePath',
|
||||
'ProcessErrors',
|
||||
function($stateParams, $q, rest, getBasePath, ProcessErrors) {
|
||||
|
||||
if ($stateParams.card) {
|
||||
return $q.when($stateParams.card);
|
||||
}
|
||||
|
||||
var managementJobId = $stateParams.management_id;
|
||||
|
||||
var url = getBasePath('system_job_templates') + managementJobId + '/';
|
||||
rest.setUrl(url);
|
||||
return rest.get()
|
||||
.then(function(data) {
|
||||
return data.data;
|
||||
}).catch(function (response) {
|
||||
ProcessErrors(null, response.data, response.status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get management job info. GET returned status: ' +
|
||||
response.status
|
||||
});
|
||||
});
|
||||
params: {
|
||||
notification_search: {}
|
||||
},
|
||||
searchPrefix: 'notification',
|
||||
views: {
|
||||
'@managementJobsList': {
|
||||
controller: 'managementJobsNotificationsController',
|
||||
templateProvider: function(NotificationsList, generateList, ParentObject) {
|
||||
// include name of parent resource in listTitle
|
||||
NotificationsList.listTitle = `${ParentObject.name}<div class='List-titleLockup'></div>Notifications`;
|
||||
let html = generateList.build({
|
||||
list: NotificationsList,
|
||||
mode: 'edit'
|
||||
});
|
||||
html = generateList.wrapPanel(html);
|
||||
return generateList.insertFormView() + html;
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
Dataset: ['NotificationsList', 'QuerySet', '$stateParams', 'GetBasePath',
|
||||
function(list, qs, $stateParams, GetBasePath) {
|
||||
let path = `${GetBasePath('notification_templates')}`;
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}
|
||||
],
|
||||
ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath) {
|
||||
let path = `${GetBasePath('system_job_templates')}${$stateParams.management_id}`;
|
||||
Rest.setUrl(path);
|
||||
return Rest.get(path).then((res) => res.data);
|
||||
}]
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
parent: 'managementJobsList',
|
||||
|
||||
@ -29,34 +29,38 @@
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: defaultUrl,
|
||||
field: 'notification_type',
|
||||
variable: 'notification_type_options',
|
||||
callback: 'choicesReadyNotifierList'
|
||||
});
|
||||
}
|
||||
|
||||
$scope.removeChoicesHere = $scope.$on('choicesReadyNotifierList', function() {
|
||||
list.fields.notification_type.searchOptions = $scope.notification_type_options;
|
||||
|
||||
if ($rootScope.addedItem) {
|
||||
$scope.addedItem = $rootScope.addedItem;
|
||||
delete $rootScope.addedItem;
|
||||
}
|
||||
$scope.notification_templates.forEach(function(notification_template, i) {
|
||||
setStatus(notification_template);
|
||||
$scope.notification_type_options.forEach(function(type) {
|
||||
if (type.value === notification_template.notification_type) {
|
||||
$scope.notification_templates[i].notification_type = type.label;
|
||||
var recent_notifications = notification_template.summary_fields.recent_notifications;
|
||||
$scope.notification_templates[i].status = recent_notifications && recent_notifications.length > 0 ? recent_notifications[0].status : "none";
|
||||
}
|
||||
});
|
||||
$scope.$on(`notification_template_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$watchCollection("notification_templates", function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
);
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched.
|
||||
function optionsRequestDataProcessing(){
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
// Set the item type label
|
||||
if (list.fields.notification_type && $scope.options &&
|
||||
$scope.options.hasOwnProperty('notification_type')) {
|
||||
$scope.options.notification_type.choices.every(function(choice) {
|
||||
if (choice[0] === item.notification_type) {
|
||||
itm.type_label = choice[1];
|
||||
var recent_notifications = itm.summary_fields.recent_notifications;
|
||||
itm.status = recent_notifications && recent_notifications.length > 0 ? recent_notifications[0].status : "none";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
setStatus(itm);
|
||||
});
|
||||
}
|
||||
|
||||
function setStatus(notification_template) {
|
||||
var html, recent_notifications = notification_template.summary_fields.recent_notifications;
|
||||
|
||||
@ -36,6 +36,7 @@ export default ['i18n', function(i18n){
|
||||
},
|
||||
notification_type: {
|
||||
label: i18n._('Type'),
|
||||
ngBind: "notification_template.type_label",
|
||||
searchType: 'select',
|
||||
searchOptions: [],
|
||||
excludeModal: true,
|
||||
@ -47,7 +48,7 @@ export default ['i18n', function(i18n){
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addNotification()',
|
||||
awToolTip: i18n._('Create a new custom inventory'),
|
||||
awToolTip: i18n._('Create a new notification template'),
|
||||
actionClass: 'btn List-buttonSubmit',
|
||||
buttonContent: '+ ' + i18n._('ADD'),
|
||||
ngShow: 'canAdd'
|
||||
|
||||
@ -12,9 +12,9 @@
|
||||
*/
|
||||
|
||||
export default ['$scope', '$rootScope', 'ProcessErrors', 'GetBasePath',
|
||||
'SelectionInit', 'templateUrl', '$state', 'Rest', '$q', 'Wait',
|
||||
'SelectionInit', 'templateUrl', '$state', 'Rest', '$q', 'Wait', '$window',
|
||||
function($scope, $rootScope, ProcessErrors, GetBasePath,
|
||||
SelectionInit, templateUrl, $state, Rest, $q, Wait) {
|
||||
SelectionInit, templateUrl, $state, Rest, $q, Wait, $window) {
|
||||
$scope.$on("linkLists", function() {
|
||||
|
||||
if ($state.current.name.split(".")[1] === "users") {
|
||||
@ -32,8 +32,15 @@ function($scope, $rootScope, ProcessErrors, GetBasePath,
|
||||
$scope.add_users = $scope.$parent.add_user_dataset.results;
|
||||
|
||||
$scope.selectedItems = [];
|
||||
$scope.$on('selectedOrDeselected', ()=>{
|
||||
throw {name: 'NotYetImplemented'};
|
||||
$scope.$on('selectedOrDeselected', function(e, value) {
|
||||
let item = value.value;
|
||||
|
||||
if (item.isSelected) {
|
||||
$scope.selectedItems.push(item.id);
|
||||
}
|
||||
else {
|
||||
$scope.selectedItems = _.remove($scope.selectedItems, { id: item.id });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -42,7 +49,7 @@ function($scope, $rootScope, ProcessErrors, GetBasePath,
|
||||
var url, listToClose,
|
||||
|
||||
payloads = $scope.selectedItems.map(function(val) {
|
||||
return {id: val.id};
|
||||
return {id: val};
|
||||
});
|
||||
|
||||
url = $scope.$parent.orgRelatedUrls[$scope.addUsersType];
|
||||
@ -69,5 +76,11 @@ function($scope, $rootScope, ProcessErrors, GetBasePath,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.linkoutUser = function(userId) {
|
||||
// Open the edit user form in a new tab so as not to navigate the user
|
||||
// away from the modal
|
||||
$window.open('/#/users/' + userId,'_blank');
|
||||
};
|
||||
});
|
||||
}];
|
||||
|
||||
@ -37,7 +37,7 @@ export default ['$stateParams', '$scope', 'UserList', 'Rest', '$state',
|
||||
}
|
||||
|
||||
$scope.addUsers = function() {
|
||||
$compile("<add-users add-users-type='admin' class='AddUsers'></add-users>")($scope);
|
||||
$compile("<add-users add-users-type='admins' class='AddUsers'></add-users>")($scope);
|
||||
};
|
||||
|
||||
$scope.editUser = function(id) {
|
||||
|
||||
@ -37,7 +37,7 @@ export default ['$stateParams', '$scope', 'OrgUserList', 'AddUserList','Rest', '
|
||||
}
|
||||
|
||||
$scope.addUsers = function() {
|
||||
$compile("<add-users add-users-type='user' class='AddUsers'></add-users>")($scope);
|
||||
$compile("<add-users add-users-type='users' class='AddUsers'></add-users>")($scope);
|
||||
};
|
||||
|
||||
$scope.editUser = function(id) {
|
||||
|
||||
@ -99,6 +99,7 @@ export default [{
|
||||
list.iterator = 'add_user';
|
||||
list.name = 'add_users';
|
||||
list.multiSelect = true;
|
||||
list.fields.username.ngClick = 'linkoutUser(add_user.id)';
|
||||
delete list.actions;
|
||||
delete list.fieldActions;
|
||||
return list;
|
||||
@ -386,6 +387,7 @@ export default [{
|
||||
}
|
||||
};
|
||||
list.searchSize = "col-lg-12 col-md-12 col-sm-12 col-xs-12";
|
||||
list.listTitle = 'Admins';
|
||||
return list;
|
||||
}],
|
||||
AddAdminList: ['UserList', function(UserList) {
|
||||
@ -394,6 +396,7 @@ export default [{
|
||||
list.iterator = 'add_user';
|
||||
list.name = 'add_users';
|
||||
list.multiSelect = true;
|
||||
list.fields.username.ngClick = 'linkoutUser(add_user.id)';
|
||||
delete list.actions;
|
||||
delete list.fieldActions;
|
||||
return list;
|
||||
|
||||
@ -45,7 +45,19 @@ export default
|
||||
let path = `${GetBasePath('job_templates')}${$stateParams.id}`;
|
||||
Rest.setUrl(path);
|
||||
return Rest.get(path).then((res) => res.data);
|
||||
}]
|
||||
}],
|
||||
UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q',
|
||||
function(Rest, GetBasePath, $stateParams, $q) {
|
||||
Rest.setUrl(GetBasePath('unified_jobs'));
|
||||
var val = $q.defer();
|
||||
Rest.options()
|
||||
.then(function(data) {
|
||||
val.resolve(data.data);
|
||||
}, function(data) {
|
||||
val.reject(data);
|
||||
});
|
||||
return val.promise;
|
||||
}]
|
||||
},
|
||||
views: {
|
||||
'@': {
|
||||
@ -119,7 +131,19 @@ export default
|
||||
let path = `${GetBasePath('workflow_job_templates')}${$stateParams.id}`;
|
||||
Rest.setUrl(path);
|
||||
return Rest.get(path).then((res) => res.data);
|
||||
}]
|
||||
}],
|
||||
UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q',
|
||||
function(Rest, GetBasePath, $stateParams, $q) {
|
||||
Rest.setUrl(GetBasePath('unified_jobs'));
|
||||
var val = $q.defer();
|
||||
Rest.options()
|
||||
.then(function(data) {
|
||||
val.resolve(data.data);
|
||||
}, function(data) {
|
||||
val.reject(data);
|
||||
});
|
||||
return val.promise;
|
||||
}]
|
||||
},
|
||||
views: {
|
||||
'@': {
|
||||
@ -190,7 +214,19 @@ export default
|
||||
let path = `${GetBasePath('projects')}${$stateParams.id}`;
|
||||
Rest.setUrl(path);
|
||||
return Rest.get(path).then((res) => res.data);
|
||||
}]
|
||||
}],
|
||||
UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q',
|
||||
function(Rest, GetBasePath, $stateParams, $q) {
|
||||
Rest.setUrl(GetBasePath('unified_jobs'));
|
||||
var val = $q.defer();
|
||||
Rest.options()
|
||||
.then(function(data) {
|
||||
val.resolve(data.data);
|
||||
}, function(data) {
|
||||
val.reject(data);
|
||||
});
|
||||
return val.promise;
|
||||
}]
|
||||
},
|
||||
views: {
|
||||
'@': {
|
||||
@ -268,6 +304,18 @@ export default
|
||||
}
|
||||
],
|
||||
ParentObject: [() =>{return {endpoint:'/api/v1/schedules'}; }],
|
||||
UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q',
|
||||
function(Rest, GetBasePath, $stateParams, $q) {
|
||||
Rest.setUrl(GetBasePath('unified_jobs'));
|
||||
var val = $q.defer();
|
||||
Rest.options()
|
||||
.then(function(data) {
|
||||
val.resolve(data.data);
|
||||
}, function(data) {
|
||||
val.reject(data);
|
||||
});
|
||||
return val.promise;
|
||||
}]
|
||||
},
|
||||
views: {
|
||||
'list@jobs': {
|
||||
|
||||
@ -14,12 +14,12 @@
|
||||
export default [
|
||||
'$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest',
|
||||
'ProcessErrors', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'Wait', 'rbacUiControlService',
|
||||
'Find', 'ToggleSchedule', 'DeleteSchedule', 'GetChoices', '$q', '$state', 'Dataset', 'ParentObject',
|
||||
'Find', 'ToggleSchedule', 'DeleteSchedule', 'GetChoices', '$q', '$state', 'Dataset', 'ParentObject', 'UnifiedJobsOptions',
|
||||
function($scope, $compile, $location, $stateParams,
|
||||
SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope,
|
||||
GetBasePath, Wait, rbacUiControlService, Find,
|
||||
ToggleSchedule, DeleteSchedule, GetChoices,
|
||||
$q, $state, Dataset, ParentObject) {
|
||||
$q, $state, Dataset, ParentObject, UnifiedJobsOptions) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
@ -43,11 +43,45 @@ export default [
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
$scope.unified_job_options = UnifiedJobsOptions.actions.GET;
|
||||
|
||||
_.forEach($scope[list.name], buildTooltips);
|
||||
// _.forEach($scope[list.name], buildTooltips);
|
||||
}
|
||||
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection(`${$scope.list.name}`, function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
);
|
||||
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.type && $scope.unified_job_options &&
|
||||
$scope.unified_job_options.hasOwnProperty('type')) {
|
||||
$scope.unified_job_options.type.choices.every(function(choice) {
|
||||
if (choice[0] === itm.summary_fields.unified_job_template.unified_job_type) {
|
||||
itm.type_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
buildTooltips(itm);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function buildTooltips(schedule) {
|
||||
var job = schedule.summary_fields.unified_job_template;
|
||||
if (schedule.enabled) {
|
||||
schedule.play_tip = 'Schedule is active. Click to stop.';
|
||||
schedule.status = 'active';
|
||||
@ -57,6 +91,18 @@ export default [
|
||||
schedule.status = 'stopped';
|
||||
schedule.status_tip = 'Schedule is stopped. Click to activate.';
|
||||
}
|
||||
|
||||
schedule.nameTip = schedule.name;
|
||||
// include the word schedule if the schedule name does not include the word schedule
|
||||
if (schedule.name.indexOf("schedule") === -1 && schedule.name.indexOf("Schedule") === -1) {
|
||||
schedule.nameTip += " schedule";
|
||||
}
|
||||
schedule.nameTip += " for ";
|
||||
if (job.name.indexOf("job") === -1 && job.name.indexOf("Job") === -1) {
|
||||
schedule.nameTip += "job ";
|
||||
}
|
||||
schedule.nameTip += job.name;
|
||||
schedule.nameTip += ". Click to edit schedule.";
|
||||
}
|
||||
|
||||
$scope.refreshSchedules = function() {
|
||||
@ -99,7 +145,7 @@ export default [
|
||||
name: 'projectSchedules.edit',
|
||||
params: {
|
||||
id: schedule.unified_job_template,
|
||||
schedule_id: schedule.id
|
||||
schedule_id: schedule.id
|
||||
}
|
||||
});
|
||||
break;
|
||||
@ -109,7 +155,7 @@ export default [
|
||||
name: 'managementJobSchedules.edit',
|
||||
params: {
|
||||
id: schedule.unified_job_template,
|
||||
schedule_id: schedule.id
|
||||
schedule_id: schedule.id
|
||||
}
|
||||
});
|
||||
break;
|
||||
@ -136,7 +182,7 @@ export default [
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -160,7 +206,7 @@ export default [
|
||||
};
|
||||
|
||||
base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
|
||||
|
||||
if (base === 'management_jobs') {
|
||||
$scope.base = base = 'system_job_templates';
|
||||
}
|
||||
@ -175,17 +221,5 @@ export default [
|
||||
$scope.formCancel = function() {
|
||||
$state.go('^', null, { reload: true });
|
||||
};
|
||||
|
||||
// @issue - believe this is no longer necessary now that parent object is resolved prior to controller initilizing
|
||||
|
||||
// Wait('start');
|
||||
|
||||
// GetChoices({
|
||||
// scope: $scope,
|
||||
// url: GetBasePath('unified_jobs'), //'/static/sample/data/types/data.json'
|
||||
// field: 'type',
|
||||
// variable: 'type_choices',
|
||||
// callback: 'choicesReady'
|
||||
// });
|
||||
}
|
||||
];
|
||||
|
||||
@ -1133,4 +1133,22 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper'])
|
||||
});
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
.directive('awPasswordToggle', [function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element) {
|
||||
$(element).click(function() {
|
||||
var buttonInnerHTML = $(element).html();
|
||||
if (buttonInnerHTML.indexOf("Show") > -1) {
|
||||
$(element).html("Hide");
|
||||
$(element).closest('.input-group').find('input').first().attr("type", "text");
|
||||
} else {
|
||||
$(element).html("Show");
|
||||
$(element).closest('.input-group').find('input').first().attr("type", "password");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
@ -846,28 +846,15 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
html += "\t" + label();
|
||||
if (field.hasShowInputButton) {
|
||||
var tooltip = i18n._("Toggle the display of plaintext.");
|
||||
field.toggleInput = function(id) {
|
||||
var buttonId = id + "_show_input_button",
|
||||
inputId = id + "_input",
|
||||
buttonInnerHTML = $(buttonId).html();
|
||||
if (buttonInnerHTML.indexOf("Show") > -1) {
|
||||
$(buttonId).html("Hide");
|
||||
$(inputId).attr("type", "text");
|
||||
} else {
|
||||
$(buttonId).html("Show");
|
||||
$(inputId).attr("type", "password");
|
||||
}
|
||||
};
|
||||
html += "\<div class='input-group";
|
||||
html += (horizontal) ? " " + getFieldWidth() : "";
|
||||
html += "'>\n";
|
||||
// TODO: make it so that the button won't show up if the mode is edit, hasShowInputButton !== true, and there are no contents in the field.
|
||||
html += "<span class='input-group-btn'>\n";
|
||||
html += "<button type='button' class='btn btn-default show_input_button Form-passwordButton' ";
|
||||
html += "<button aw-password-toggle type='button' class='btn btn-default show_input_button Form-passwordButton' ";
|
||||
html += buildId(field, fld + "_show_input_button", this.form);
|
||||
html += `aw-tool-tip='${tooltip}'} aw-tip-placement='top'`;
|
||||
html += "tabindex='-1' ";
|
||||
html += "ng-click='" + fld + "_field.toggleInput(\"#" + this.form.name + "_" + fld + "\")'";
|
||||
html += (field.ngDisabled) ? "ng-disabled='" + field.ngDisabled + "'" : "";
|
||||
html += ">\n" + field.showInputInnerHTML;
|
||||
html += "\n</button>\n";
|
||||
|
||||
@ -18,13 +18,23 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
|
||||
// grab a single model from the cache, if present
|
||||
if (cache.get(path)) {
|
||||
defer.resolve({[name] : new DjangoSearchModel(name, path, cache.get(path), relations)});
|
||||
defer.resolve({
|
||||
models: {
|
||||
[name] : new DjangoSearchModel(name, path, cache.get(path), relations)
|
||||
},
|
||||
options: cache.get(path)
|
||||
});
|
||||
} else {
|
||||
this.url = path;
|
||||
resolve = this.options(path)
|
||||
.then((res) => {
|
||||
base = res.data.actions.GET;
|
||||
defer.resolve({[name]: new DjangoSearchModel(name, path, base, relations)});
|
||||
defer.resolve({
|
||||
models: {
|
||||
[name]: new DjangoSearchModel(name, path, base, relations)
|
||||
},
|
||||
options: res
|
||||
});
|
||||
});
|
||||
}
|
||||
return defer.promise;
|
||||
@ -76,9 +86,9 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
if (Array.isArray(value)){
|
||||
return _.map(value, (item) => {
|
||||
return `${key.split('__').join(':')}:${item}`;
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
else {
|
||||
return `${key.split('__').join(':')}:${value}`;
|
||||
}
|
||||
},
|
||||
|
||||
@ -15,8 +15,9 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
||||
path = GetBasePath($scope.basePath) || $scope.basePath;
|
||||
relations = getRelationshipFields($scope.dataset.results);
|
||||
$scope.searchTags = stripDefaultParams($state.params[`${$scope.iterator}_search`]);
|
||||
qs.initFieldset(path, $scope.djangoModel, relations).then((models) => {
|
||||
$scope.models = models;
|
||||
qs.initFieldset(path, $scope.djangoModel, relations).then((data) => {
|
||||
$scope.models = data.models;
|
||||
$scope.$emit(`${$scope.list.iterator}_options`, data.options);
|
||||
});
|
||||
}
|
||||
|
||||
@ -102,12 +103,12 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
||||
params.page = '1';
|
||||
queryset = _.merge(queryset, params, (objectValue, sourceValue, key, object) => {
|
||||
if (object[key] && object[key] !== sourceValue){
|
||||
return [object[key], sourceValue];
|
||||
return [object[key], sourceValue];
|
||||
}
|
||||
else {
|
||||
// // https://lodash.com/docs/3.10.1#merge
|
||||
// If customizer fn returns undefined merging is handled by default _.merge algorithm
|
||||
return undefined;
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
// https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic
|
||||
|
||||
@ -31,7 +31,7 @@ export default function($stateProvider) {
|
||||
order_by: "name"
|
||||
},
|
||||
dynamic: true,
|
||||
squash: true
|
||||
squash: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -4,10 +4,11 @@
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', 'Alert',
|
||||
'TemplateList', 'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath',
|
||||
'InitiatePlaybookRun', 'Wait', '$state', '$filter', 'Dataset', 'rbacUiControlService', 'TemplatesService',
|
||||
'QuerySet', 'GetChoices', 'TemplateCopyService',
|
||||
export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest',
|
||||
'Alert','TemplateList', 'Prompt', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'InitiatePlaybookRun', 'Wait', '$state', '$filter',
|
||||
'Dataset', 'rbacUiControlService', 'TemplatesService','QuerySet',
|
||||
'GetChoices', 'TemplateCopyService',
|
||||
function(
|
||||
$scope, $rootScope, $location, $stateParams, Rest, Alert,
|
||||
TemplateList, Prompt, ClearScope, ProcessErrors, GetBasePath,
|
||||
@ -36,38 +37,40 @@ export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', 'Al
|
||||
$scope.list = list;
|
||||
$scope[`${list.iterator}_dataset`] = Dataset.data;
|
||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
||||
$scope.options = {};
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
}
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
$scope.removeChoicesReady();
|
||||
$scope.$on(`${list.iterator}_options`, function(event, data){
|
||||
$scope.options = data.data.actions.GET;
|
||||
optionsRequestDataProcessing();
|
||||
});
|
||||
|
||||
$scope.$watchCollection('templates', function() {
|
||||
optionsRequestDataProcessing();
|
||||
}
|
||||
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
);
|
||||
// iterate over the list and add fields like type label, after the
|
||||
// OPTIONS request returns, or the list is sorted/paginated/searched
|
||||
function optionsRequestDataProcessing(){
|
||||
$scope[list.name].forEach(function(item, item_idx) {
|
||||
var itm = $scope[list.name][item_idx];
|
||||
|
||||
// Set the item type label
|
||||
if (list.fields.type) {
|
||||
$scope.type_choices.every(function(choice) {
|
||||
if (choice.value === item.type) {
|
||||
itm.type_label = choice.label;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: GetBasePath('unified_job_templates'),
|
||||
field: 'type',
|
||||
variable: 'type_choices',
|
||||
callback: 'choicesReady'
|
||||
// Set the item type label
|
||||
if (list.fields.type && $scope.options.hasOwnProperty('type')) {
|
||||
$scope.options.type.choices.every(function(choice) {
|
||||
if (choice[0] === item.type) {
|
||||
itm.type_label = choice[1];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$scope.$on(`ws-jobs`, function () {
|
||||
// @issue - this is no longer quite as ham-fisted but I'd like for someone else to take a peek
|
||||
// calling $state.reload(); here was problematic when launching a job because job launch also
|
||||
|
||||
@ -115,7 +115,7 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesA
|
||||
},
|
||||
'jobTemplateList@templates.editWorkflowJobTemplate.workflowMaker': {
|
||||
templateProvider: function(WorkflowMakerJobTemplateList, generateList) {
|
||||
//debugger;
|
||||
|
||||
let html = generateList.build({
|
||||
list: WorkflowMakerJobTemplateList,
|
||||
input_type: 'radio',
|
||||
|
||||
@ -183,6 +183,7 @@
|
||||
<div class="StandardOut-panelHeaderText">
|
||||
<i class="WorkflowResults-statusResultIcon
|
||||
fa icon-job-{{ workflow.status }}"
|
||||
ng-show="stdoutFullScreen"
|
||||
aw-tool-tip="Job {{status_label}}"
|
||||
aw-tip-placement="top"
|
||||
data-original-title>
|
||||
|
||||
@ -12,7 +12,6 @@ module.exports = {
|
||||
]
|
||||
},
|
||||
options: {
|
||||
open: 'external',
|
||||
proxy: {
|
||||
target: `https://${django_host}:${django_port}`,
|
||||
ws: true
|
||||
|
||||
@ -34,15 +34,15 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:153
|
||||
#: client/src/forms/JobTemplates.js:414
|
||||
#: client/src/forms/Organizations.js:75
|
||||
#: client/src/forms/Projects.js:238
|
||||
#: client/src/forms/Projects.js:237
|
||||
#: client/src/forms/Teams.js:86
|
||||
#: client/src/forms/Workflows.js:126
|
||||
#: client/src/forms/Workflows.js:127
|
||||
#: client/src/inventory-scripts/inventory-scripts.list.js:45
|
||||
#: client/src/lists/Credentials.js:59
|
||||
#: client/src/lists/Inventories.js:68
|
||||
#: client/src/lists/Projects.js:67
|
||||
#: client/src/lists/Teams.js:50
|
||||
#: client/src/lists/Templates.js:61
|
||||
#: client/src/lists/Templates.js:62
|
||||
#: client/src/lists/Users.js:58
|
||||
#: client/src/notifications/notificationTemplates.list.js:52
|
||||
msgid "ADD"
|
||||
@ -81,7 +81,7 @@ msgid "Account Token"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/dashboard/lists/job-templates/job-templates-list.partial.html:20
|
||||
#: client/src/shared/list-generator/list-generator.factory.js:502
|
||||
#: client/src/shared/list-generator/list-generator.factory.js:538
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
@ -94,7 +94,7 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:150
|
||||
#: client/src/forms/Organizations.js:72
|
||||
#: client/src/forms/Teams.js:83
|
||||
#: client/src/forms/Workflows.js:123
|
||||
#: client/src/forms/Workflows.js:124
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
|
||||
@ -119,8 +119,8 @@ msgid "Add Project"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:459
|
||||
#: client/src/forms/Workflows.js:171
|
||||
#: client/src/shared/form-generator.js:1703
|
||||
#: client/src/forms/Workflows.js:172
|
||||
#: client/src/shared/form-generator.js:1707
|
||||
msgid "Add Survey"
|
||||
msgstr ""
|
||||
|
||||
@ -136,7 +136,7 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:151
|
||||
#: client/src/forms/JobTemplates.js:412
|
||||
#: client/src/forms/Organizations.js:73
|
||||
#: client/src/forms/Projects.js:236
|
||||
#: client/src/forms/Projects.js:235
|
||||
msgid "Add a permission"
|
||||
msgstr ""
|
||||
|
||||
@ -219,6 +219,10 @@ msgstr ""
|
||||
msgid "Authorize Password"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:101
|
||||
msgid "Azure AD"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:80
|
||||
msgid "Base path used for locating playbooks. Directories found inside this path will be listed in the playbook directory drop-down. Together the base path and selected playbook directory provide the full path used to locate playbooks."
|
||||
msgstr ""
|
||||
@ -235,11 +239,11 @@ msgstr ""
|
||||
msgid "CREDENTIALS"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:195
|
||||
#: client/src/forms/Projects.js:194
|
||||
msgid "Cache Timeout"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:184
|
||||
#: client/src/forms/Projects.js:183
|
||||
msgid "Cache Timeout%s (seconds)%s"
|
||||
msgstr ""
|
||||
|
||||
@ -265,7 +269,8 @@ msgstr ""
|
||||
msgid "Call to get project failed. GET status:"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/form-generator.js:1691
|
||||
#: client/src/configuration/configuration.controller.js:414
|
||||
#: client/src/shared/form-generator.js:1695
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
@ -281,6 +286,10 @@ msgstr ""
|
||||
msgid "Canceled. Click for details"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:82
|
||||
msgid "Change %s under \"Configure Tower\" to change this location."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/form-generator.js:1084
|
||||
msgid "Choose a %s"
|
||||
msgstr ""
|
||||
@ -289,7 +298,7 @@ msgstr ""
|
||||
msgid "Choose your license file, agree to the End User License Agreement, and click submit."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:152
|
||||
#: client/src/forms/Projects.js:151
|
||||
msgid "Clean"
|
||||
msgstr ""
|
||||
|
||||
@ -317,7 +326,7 @@ msgstr ""
|
||||
msgid "Client Secret"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/form-generator.js:1695
|
||||
#: client/src/shared/form-generator.js:1699
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
@ -346,6 +355,14 @@ msgstr ""
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/configuration.controller.js:421
|
||||
msgid "Confirm Reset"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/configuration.controller.js:430
|
||||
msgid "Confirm factory reset"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:255
|
||||
#: client/src/forms/JobTemplates.js:273
|
||||
#: client/src/forms/WorkflowMaker.js:141
|
||||
@ -357,11 +374,11 @@ msgstr ""
|
||||
msgid "Control the level of output ansible will produce as the playbook executes."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:99
|
||||
#: client/src/lists/Templates.js:100
|
||||
msgid "Copy"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:102
|
||||
#: client/src/lists/Templates.js:103
|
||||
msgid "Copy template"
|
||||
msgstr ""
|
||||
|
||||
@ -402,7 +419,7 @@ msgstr ""
|
||||
msgid "Create a new team"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:59
|
||||
#: client/src/lists/Templates.js:60
|
||||
msgid "Create a new template"
|
||||
msgstr ""
|
||||
|
||||
@ -435,7 +452,7 @@ msgstr ""
|
||||
msgid "Custom Script"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/app.js:405
|
||||
#: client/src/app.js:409
|
||||
msgid "DASHBOARD"
|
||||
msgstr ""
|
||||
|
||||
@ -451,7 +468,7 @@ msgstr ""
|
||||
#: client/src/lists/Credentials.js:90
|
||||
#: client/src/lists/Inventories.js:92
|
||||
#: client/src/lists/Teams.js:77
|
||||
#: client/src/lists/Templates.js:123
|
||||
#: client/src/lists/Templates.js:125
|
||||
#: client/src/lists/Users.js:87
|
||||
#: client/src/notifications/notificationTemplates.list.js:89
|
||||
msgid "Delete"
|
||||
@ -473,7 +490,7 @@ msgstr ""
|
||||
msgid "Delete notification"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:162
|
||||
#: client/src/forms/Projects.js:161
|
||||
msgid "Delete on Update"
|
||||
msgstr ""
|
||||
|
||||
@ -481,7 +498,7 @@ msgstr ""
|
||||
msgid "Delete team"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:126
|
||||
#: client/src/lists/Templates.js:128
|
||||
msgid "Delete template"
|
||||
msgstr ""
|
||||
|
||||
@ -489,7 +506,7 @@ msgstr ""
|
||||
msgid "Delete the job"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:164
|
||||
#: client/src/forms/Projects.js:163
|
||||
msgid "Delete the local repository in its entirety prior to performing an update."
|
||||
msgstr ""
|
||||
|
||||
@ -505,7 +522,7 @@ msgstr ""
|
||||
msgid "Delete user"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:164
|
||||
#: client/src/forms/Projects.js:163
|
||||
msgid "Depending on the size of the repository this may significantly increase the amount of time required to complete an update."
|
||||
msgstr ""
|
||||
|
||||
@ -517,7 +534,7 @@ msgstr ""
|
||||
#: client/src/forms/Teams.js:34
|
||||
#: client/src/forms/Users.js:142
|
||||
#: client/src/forms/Users.js:167
|
||||
#: client/src/forms/Workflows.js:40
|
||||
#: client/src/forms/Workflows.js:41
|
||||
#: client/src/inventory-scripts/inventory-scripts.form.js:32
|
||||
#: client/src/inventory-scripts/inventory-scripts.list.js:25
|
||||
#: client/src/lists/Credentials.js:34
|
||||
@ -550,6 +567,12 @@ msgstr ""
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:70
|
||||
#: client/src/configuration/configuration.controller.js:159
|
||||
#: client/src/configuration/configuration.controller.js:212
|
||||
msgid "Discard changes"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Teams.js:148
|
||||
msgid "Dissasociate permission from team"
|
||||
msgstr ""
|
||||
@ -567,7 +590,7 @@ msgstr ""
|
||||
msgid "Drag and drop your custom inventory script file here or create one in the field to import your custom inventory."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:175
|
||||
#: client/src/forms/Projects.js:174
|
||||
msgid "Each time a job runs using this project, perform an update to the local repository prior to starting the job."
|
||||
msgstr ""
|
||||
|
||||
@ -576,7 +599,7 @@ msgstr ""
|
||||
#: client/src/lists/Credentials.js:71
|
||||
#: client/src/lists/Inventories.js:78
|
||||
#: client/src/lists/Teams.js:60
|
||||
#: client/src/lists/Templates.js:107
|
||||
#: client/src/lists/Templates.js:108
|
||||
#: client/src/lists/Users.js:68
|
||||
#: client/src/notifications/notificationTemplates.list.js:63
|
||||
#: client/src/notifications/notificationTemplates.list.js:72
|
||||
@ -584,8 +607,8 @@ msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:466
|
||||
#: client/src/forms/Workflows.js:178
|
||||
#: client/src/shared/form-generator.js:1707
|
||||
#: client/src/forms/Workflows.js:179
|
||||
#: client/src/shared/form-generator.js:1711
|
||||
msgid "Edit Survey"
|
||||
msgstr ""
|
||||
|
||||
@ -613,7 +636,7 @@ msgstr ""
|
||||
msgid "Edit team"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:109
|
||||
#: client/src/lists/Templates.js:110
|
||||
msgid "Edit template"
|
||||
msgstr ""
|
||||
|
||||
@ -646,7 +669,7 @@ msgstr ""
|
||||
msgid "Enables creation of a provisioning callback URL. Using the URL a host can contact Tower and request a configuration update using this job template."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/helpers/Credentials.js:308
|
||||
#: client/src/helpers/Credentials.js:306
|
||||
msgid "Encrypted credentials are not supported."
|
||||
msgstr ""
|
||||
|
||||
@ -670,6 +693,10 @@ msgstr ""
|
||||
msgid "Enter the hostname or IP address which corresponds to your VMware vCenter."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/configuration.controller.js:272
|
||||
#: client/src/configuration/configuration.controller.js:350
|
||||
#: client/src/configuration/configuration.controller.js:384
|
||||
#: client/src/configuration/configuration.controller.js:403
|
||||
#: client/src/controllers/Projects.js:133
|
||||
#: client/src/controllers/Projects.js:155
|
||||
#: client/src/controllers/Projects.js:180
|
||||
@ -684,8 +711,8 @@ msgstr ""
|
||||
#: client/src/controllers/Users.js:267
|
||||
#: client/src/controllers/Users.js:321
|
||||
#: client/src/controllers/Users.js:94
|
||||
#: client/src/helpers/Credentials.js:312
|
||||
#: client/src/helpers/Credentials.js:328
|
||||
#: client/src/helpers/Credentials.js:310
|
||||
#: client/src/helpers/Credentials.js:326
|
||||
#: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:119
|
||||
msgid "Error!"
|
||||
msgstr ""
|
||||
@ -711,8 +738,8 @@ msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:352
|
||||
#: client/src/forms/JobTemplates.js:364
|
||||
#: client/src/forms/Workflows.js:71
|
||||
#: client/src/forms/Workflows.js:83
|
||||
#: client/src/forms/Workflows.js:72
|
||||
#: client/src/forms/Workflows.js:84
|
||||
msgid "Extra Variables"
|
||||
msgstr ""
|
||||
|
||||
@ -732,7 +759,7 @@ msgstr ""
|
||||
msgid "Failed to add new user. POST returned status:"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/helpers/Credentials.js:313
|
||||
#: client/src/helpers/Credentials.js:311
|
||||
msgid "Failed to create new Credential. POST status:"
|
||||
msgstr ""
|
||||
|
||||
@ -753,7 +780,15 @@ msgstr ""
|
||||
msgid "Failed to retrieve user: %s. GET status:"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/helpers/Credentials.js:329
|
||||
#: client/src/configuration/configuration.controller.js:351
|
||||
msgid "Failed to save settings. Returned status:"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/configuration.controller.js:385
|
||||
msgid "Failed to save toggle settings. Returned status:"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/helpers/Credentials.js:327
|
||||
msgid "Failed to update Credential. PUT status:"
|
||||
msgstr ""
|
||||
|
||||
@ -802,6 +837,22 @@ msgstr ""
|
||||
msgid "Forks"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:102
|
||||
msgid "Github"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:103
|
||||
msgid "Github Org"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:104
|
||||
msgid "Github Team"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:105
|
||||
msgid "Google OAuth2"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Teams.js:118
|
||||
msgid "Granted Permissions"
|
||||
msgstr ""
|
||||
@ -949,7 +1000,7 @@ msgstr ""
|
||||
msgid "JOB TEMPLATE"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/app.js:425
|
||||
#: client/src/app.js:429
|
||||
#: client/src/dashboard/graphs/job-status/job-status-graph.directive.js:113
|
||||
#: client/src/main-menu/main-menu.partial.html:122
|
||||
#: client/src/main-menu/main-menu.partial.html:43
|
||||
@ -963,7 +1014,7 @@ msgstr ""
|
||||
msgid "Job Tags"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:64
|
||||
#: client/src/lists/Templates.js:65
|
||||
msgid "Job Template"
|
||||
msgstr ""
|
||||
|
||||
@ -986,6 +1037,10 @@ msgstr ""
|
||||
msgid "Jobs"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:106
|
||||
msgid "LDAP"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/main-menu/main-menu.partial.html:83
|
||||
msgid "LOG OUT"
|
||||
msgstr ""
|
||||
@ -996,8 +1051,8 @@ msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:340
|
||||
#: client/src/forms/JobTemplates.js:345
|
||||
#: client/src/forms/Workflows.js:59
|
||||
#: client/src/forms/Workflows.js:64
|
||||
#: client/src/forms/Workflows.js:60
|
||||
#: client/src/forms/Workflows.js:65
|
||||
#: client/src/lists/Templates.js:47
|
||||
msgid "Labels"
|
||||
msgstr ""
|
||||
@ -1012,8 +1067,8 @@ msgid "Last Updated"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/PortalJobTemplates.js:39
|
||||
#: client/src/lists/Templates.js:83
|
||||
#: client/src/shared/form-generator.js:1699
|
||||
#: client/src/lists/Templates.js:84
|
||||
#: client/src/shared/form-generator.js:1703
|
||||
msgid "Launch"
|
||||
msgstr ""
|
||||
|
||||
@ -1049,19 +1104,19 @@ msgstr ""
|
||||
msgid "Limit"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/socket/socket.service.js:176
|
||||
#: client/src/shared/socket/socket.service.js:170
|
||||
msgid "Live events: attempting to connect to the Tower server."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/socket/socket.service.js:180
|
||||
#: client/src/shared/socket/socket.service.js:174
|
||||
msgid "Live events: connected. Pages containing job status information will automatically update in real-time."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/socket/socket.service.js:184
|
||||
#: client/src/shared/socket/socket.service.js:178
|
||||
msgid "Live events: error connecting to the Tower server."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/form-generator.js:1962
|
||||
#: client/src/shared/form-generator.js:1977
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
@ -1131,7 +1186,7 @@ msgstr ""
|
||||
#: client/src/forms/Users.js:139
|
||||
#: client/src/forms/Users.js:164
|
||||
#: client/src/forms/Users.js:190
|
||||
#: client/src/forms/Workflows.js:33
|
||||
#: client/src/forms/Workflows.js:34
|
||||
#: client/src/inventory-scripts/inventory-scripts.form.js:25
|
||||
#: client/src/inventory-scripts/inventory-scripts.list.js:20
|
||||
#: client/src/lists/CompletedJobs.js:43
|
||||
@ -1195,7 +1250,7 @@ msgid "New User"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Workflows.js:19
|
||||
msgid "New Workflow"
|
||||
msgid "New Workflow Job Template"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/controllers/Users.js:174
|
||||
@ -1293,7 +1348,7 @@ msgid "OpenStack domains define administrative boundaries. It is only needed for
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:347
|
||||
#: client/src/forms/Workflows.js:66
|
||||
#: client/src/forms/Workflows.js:67
|
||||
msgid "Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs in the Tower display."
|
||||
msgstr ""
|
||||
|
||||
@ -1309,8 +1364,8 @@ msgstr ""
|
||||
#: client/src/forms/Projects.js:49
|
||||
#: client/src/forms/Teams.js:39
|
||||
#: client/src/forms/Users.js:59
|
||||
#: client/src/forms/Workflows.js:46
|
||||
#: client/src/forms/Workflows.js:52
|
||||
#: client/src/forms/Workflows.js:47
|
||||
#: client/src/forms/Workflows.js:53
|
||||
#: client/src/inventory-scripts/inventory-scripts.form.js:37
|
||||
#: client/src/inventory-scripts/inventory-scripts.list.js:30
|
||||
#: client/src/lists/Inventories.js:52
|
||||
@ -1337,7 +1392,7 @@ msgid "PASSWORD"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/organizations/list/organizations-list.partial.html:44
|
||||
#: client/src/shared/form-generator.js:1865
|
||||
#: client/src/shared/form-generator.js:1880
|
||||
#: client/src/shared/list-generator/list-generator.factory.js:245
|
||||
msgid "PLEASE ADD ITEMS TO THIS LIST"
|
||||
msgstr ""
|
||||
@ -1356,7 +1411,7 @@ msgid "Pagerduty subdomain"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:358
|
||||
#: client/src/forms/Workflows.js:77
|
||||
#: client/src/forms/Workflows.js:78
|
||||
msgid "Pass extra command line variables to the playbook. This is the %s or %s command line parameter for %s. Provide key/value pairs using either YAML or JSON."
|
||||
msgstr ""
|
||||
|
||||
@ -1419,8 +1474,8 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:142
|
||||
#: client/src/forms/JobTemplates.js:403
|
||||
#: client/src/forms/Organizations.js:64
|
||||
#: client/src/forms/Projects.js:228
|
||||
#: client/src/forms/Workflows.js:115
|
||||
#: client/src/forms/Projects.js:227
|
||||
#: client/src/forms/Workflows.js:116
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
@ -1493,9 +1548,9 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:91
|
||||
#: client/src/forms/JobTemplates.js:396
|
||||
#: client/src/forms/Organizations.js:57
|
||||
#: client/src/forms/Projects.js:220
|
||||
#: client/src/forms/Projects.js:219
|
||||
#: client/src/forms/Teams.js:110
|
||||
#: client/src/forms/Workflows.js:108
|
||||
#: client/src/forms/Workflows.js:109
|
||||
msgid "Please save before assigning permissions"
|
||||
msgstr ""
|
||||
|
||||
@ -1508,7 +1563,7 @@ msgstr ""
|
||||
msgid "Please save before assigning to teams"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Workflows.js:184
|
||||
#: client/src/forms/Workflows.js:185
|
||||
msgid "Please save before defining the workflow graph"
|
||||
msgstr ""
|
||||
|
||||
@ -1593,7 +1648,7 @@ msgstr ""
|
||||
msgid "Project Name"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:101
|
||||
#: client/src/forms/Projects.js:100
|
||||
msgid "Project Path"
|
||||
msgstr ""
|
||||
|
||||
@ -1638,6 +1693,10 @@ msgstr ""
|
||||
msgid "Provisioning Callback URL"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:107
|
||||
msgid "RADIUS"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/dashboard/lists/jobs/jobs-list.partial.html:4
|
||||
msgid "RECENT JOB RUNS"
|
||||
msgstr ""
|
||||
@ -1684,7 +1743,7 @@ msgstr ""
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:154
|
||||
#: client/src/forms/Projects.js:153
|
||||
msgid "Remove any local modifications prior to performing an update."
|
||||
msgstr ""
|
||||
|
||||
@ -1692,6 +1751,20 @@ msgstr ""
|
||||
msgid "Request License"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-azure.form.js:41
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-github-org.form.js:31
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-github-team.form.js:31
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-github.form.js:27
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-google-oauth2.form.js:39
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-ldap.form.js:87
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-radius.form.js:32
|
||||
#: client/src/configuration/auth-form/sub-forms/auth-saml.form.js:59
|
||||
#: client/src/configuration/jobs-form/configuration-jobs.form.js:55
|
||||
#: client/src/configuration/system-form/configuration-system.form.js:41
|
||||
#: client/src/configuration/ui-form/configuration-ui.form.js:35
|
||||
msgid "Reset All"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Projects.js:42
|
||||
msgid "Revision"
|
||||
msgstr ""
|
||||
@ -1704,26 +1777,30 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:120
|
||||
#: client/src/forms/Inventories.js:166
|
||||
#: client/src/forms/Organizations.js:88
|
||||
#: client/src/forms/Projects.js:250
|
||||
#: client/src/forms/Projects.js:249
|
||||
#: client/src/forms/Teams.js:137
|
||||
#: client/src/forms/Teams.js:99
|
||||
#: client/src/forms/Users.js:201
|
||||
msgid "Role"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:108
|
||||
msgid "SAML"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/controllers/Projects.js:657
|
||||
msgid "SCM Branch"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:155
|
||||
#: client/src/forms/Projects.js:154
|
||||
msgid "SCM Clean"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:131
|
||||
#: client/src/forms/Projects.js:130
|
||||
msgid "SCM Credential"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:166
|
||||
#: client/src/forms/Projects.js:165
|
||||
msgid "SCM Delete"
|
||||
msgstr ""
|
||||
|
||||
@ -1736,7 +1813,7 @@ msgid "SCM Type"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/dashboard/graphs/dashboard-graphs.partial.html:49
|
||||
#: client/src/forms/Projects.js:176
|
||||
#: client/src/forms/Projects.js:175
|
||||
msgid "SCM Update"
|
||||
msgstr ""
|
||||
|
||||
@ -1744,7 +1821,7 @@ msgstr ""
|
||||
msgid "SCM Update Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:146
|
||||
#: client/src/forms/Projects.js:145
|
||||
msgid "SCM Update Options"
|
||||
msgstr ""
|
||||
|
||||
@ -1765,7 +1842,7 @@ msgstr ""
|
||||
msgid "SIGN IN WITH"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/app.js:509
|
||||
#: client/src/app.js:513
|
||||
msgid "SOCKETS"
|
||||
msgstr ""
|
||||
|
||||
@ -1798,11 +1875,17 @@ msgstr ""
|
||||
msgid "Save"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:81
|
||||
#: client/src/configuration/configuration.controller.js:170
|
||||
#: client/src/configuration/configuration.controller.js:220
|
||||
msgid "Save changes"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/license/license.partial.html:122
|
||||
msgid "Save successful!"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:91
|
||||
#: client/src/lists/Templates.js:92
|
||||
msgid "Schedule"
|
||||
msgstr ""
|
||||
|
||||
@ -1814,7 +1897,7 @@ msgstr ""
|
||||
msgid "Schedule future SCM updates"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:94
|
||||
#: client/src/lists/Templates.js:95
|
||||
msgid "Schedule future job template runs"
|
||||
msgstr ""
|
||||
|
||||
@ -1838,8 +1921,21 @@ msgstr ""
|
||||
msgid "Security Token Service (STS) is a web service that enables you to request temporary, limited-privilege credentials for AWS Identity and Access Management (IAM) users."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/form-generator.js:1691
|
||||
msgid "Select"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/jobs-form/configuration-jobs.controller.js:87
|
||||
#: client/src/configuration/ui-form/configuration-ui.controller.js:82
|
||||
msgid "Select commands"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:98
|
||||
msgid "Select from the list of directories found in the base path.Together the base path and the playbook directory provide the full path used to locate playbooks."
|
||||
msgid "Select from the list of directories found in the Project Base Path. Together the base path and the playbook directory provide the full path used to locate playbooks."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:226
|
||||
msgid "Select group types"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:152
|
||||
@ -1945,7 +2041,7 @@ msgid "Split up your organization to associate content and control permissions f
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/PortalJobTemplates.js:42
|
||||
#: client/src/lists/Templates.js:86
|
||||
#: client/src/lists/Templates.js:87
|
||||
msgid "Start a job using this template"
|
||||
msgstr ""
|
||||
|
||||
@ -2017,7 +2113,7 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:126
|
||||
#: client/src/forms/Inventories.js:173
|
||||
#: client/src/forms/Organizations.js:95
|
||||
#: client/src/forms/Projects.js:256
|
||||
#: client/src/forms/Projects.js:255
|
||||
msgid "Team Roles"
|
||||
msgstr ""
|
||||
|
||||
@ -2093,6 +2189,14 @@ msgstr ""
|
||||
msgid "There is no SCM update information available for this project. An update has not yet been completed. If you have not already done so, start an update for this project."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/configuration.controller.js:273
|
||||
msgid "There was an error resetting value. Returned status:"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/configuration.controller.js:404
|
||||
msgid "There was an error resetting values. Returned status:"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/helpers/Credentials.js:138
|
||||
msgid "This is the tenant name. This value is usually the same as the username."
|
||||
msgstr ""
|
||||
@ -2114,6 +2218,10 @@ msgstr ""
|
||||
msgid "This value does not match the password you entered previously. Please confirm that password."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/configuration.controller.js:429
|
||||
msgid "This will reset all configuration values to their factory defaults. Are you sure you want to proceed?"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/dashboard/lists/jobs/jobs-list.partial.html:14
|
||||
msgid "Time"
|
||||
msgstr ""
|
||||
@ -2122,7 +2230,7 @@ msgstr ""
|
||||
msgid "Time Remaining"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:192
|
||||
#: client/src/forms/Projects.js:191
|
||||
msgid "Time in seconds to consider a project to be current. During job runs and callbacks the task system will evaluate the timestamp of the latest project update. If it is older than Cache Timeout, it is not considered current, and a new project update will be performed."
|
||||
msgstr ""
|
||||
|
||||
@ -2192,7 +2300,7 @@ msgstr ""
|
||||
msgid "Update in Progress"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:173
|
||||
#: client/src/forms/Projects.js:172
|
||||
msgid "Update on Launch"
|
||||
msgstr ""
|
||||
|
||||
@ -2200,11 +2308,6 @@ msgstr ""
|
||||
msgid "Upgrade"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Projects.js:100
|
||||
#: client/src/forms/Projects.js:82
|
||||
msgid "Use %s in your environment settings file to determine the base path value."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/notifications/notificationTemplates.form.js:404
|
||||
msgid "Use SSL"
|
||||
msgstr ""
|
||||
@ -2221,7 +2324,7 @@ msgstr ""
|
||||
#: client/src/forms/Inventories.js:115
|
||||
#: client/src/forms/Inventories.js:161
|
||||
#: client/src/forms/Organizations.js:83
|
||||
#: client/src/forms/Projects.js:245
|
||||
#: client/src/forms/Projects.js:244
|
||||
#: client/src/forms/Teams.js:94
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
@ -2291,7 +2394,7 @@ msgstr ""
|
||||
#: client/src/lists/Credentials.js:80
|
||||
#: client/src/lists/Inventories.js:85
|
||||
#: client/src/lists/Teams.js:69
|
||||
#: client/src/lists/Templates.js:115
|
||||
#: client/src/lists/Templates.js:117
|
||||
#: client/src/lists/Users.js:78
|
||||
#: client/src/notifications/notificationTemplates.list.js:80
|
||||
msgid "View"
|
||||
@ -2306,8 +2409,8 @@ msgid "View JSON examples at %s"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/JobTemplates.js:450
|
||||
#: client/src/forms/Workflows.js:162
|
||||
#: client/src/shared/form-generator.js:1711
|
||||
#: client/src/forms/Workflows.js:163
|
||||
#: client/src/shared/form-generator.js:1715
|
||||
msgid "View Survey"
|
||||
msgstr ""
|
||||
|
||||
@ -2347,7 +2450,7 @@ msgstr ""
|
||||
msgid "View team"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:117
|
||||
#: client/src/lists/Templates.js:119
|
||||
msgid "View template"
|
||||
msgstr ""
|
||||
|
||||
@ -2363,6 +2466,16 @@ msgstr ""
|
||||
msgid "View user"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Workflows.js:22
|
||||
msgid "WORKFLOW"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:68
|
||||
#: client/src/configuration/configuration.controller.js:157
|
||||
#: client/src/configuration/configuration.controller.js:210
|
||||
msgid "Warning: Unsaved Changes"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/login/loginModal/loginModal.partial.html:17
|
||||
msgid "Welcome to Ansible Tower! Please sign in."
|
||||
msgstr ""
|
||||
@ -2376,12 +2489,12 @@ msgstr ""
|
||||
msgid "When this template is submitted as a job, setting the type to %s will execute the playbook, running tasks on the selected hosts."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/forms/Workflows.js:186
|
||||
#: client/src/shared/form-generator.js:1715
|
||||
#: client/src/forms/Workflows.js:187
|
||||
#: client/src/shared/form-generator.js:1719
|
||||
msgid "Workflow Editor"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/lists/Templates.js:69
|
||||
#: client/src/lists/Templates.js:70
|
||||
msgid "Workflow Job Template"
|
||||
msgstr ""
|
||||
|
||||
@ -2397,6 +2510,12 @@ msgstr ""
|
||||
msgid "You do not have permission to add a user."
|
||||
msgstr ""
|
||||
|
||||
#: client/src/configuration/auth-form/configuration-auth.controller.js:67
|
||||
#: client/src/configuration/configuration.controller.js:156
|
||||
#: client/src/configuration/configuration.controller.js:209
|
||||
msgid "You have unsaved changes. Would you like to proceed <strong>without</strong> saving?"
|
||||
msgstr ""
|
||||
|
||||
#: client/src/shared/form-generator.js:960
|
||||
msgid "Your password must be %d characters long."
|
||||
msgstr ""
|
||||
|
||||
@ -100,7 +100,7 @@ var dev = {
|
||||
'select2': path.resolve() + '/node_modules/select2/dist/js/select2.full.js'
|
||||
}
|
||||
},
|
||||
devtool: 'sourcemap',
|
||||
devtool: 'inline-source-map',
|
||||
watch: true,
|
||||
};
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
The requirements.txt and requirements_ansible.txt files are generated from requirements.in and requirements_ansible.in, respectively, using `pip-tools` `pip-compile`.
|
||||
The requirements.txt and requirements_ansible.txt files are generated from requirements.in and requirements_ansible.in, respectively, using `pip-tools` `pip-compile`. The following commands should do this if ran inside the tower_tools container.
|
||||
|
||||
```
|
||||
virtualenv /buildit
|
||||
|
||||
@ -40,6 +40,7 @@ python-saml==2.2.0
|
||||
python-social-auth==0.2.21
|
||||
redbaron==0.6.2
|
||||
requests-futures==0.9.7
|
||||
service-identity==16.0.0
|
||||
shade==1.13.1
|
||||
slackclient==1.0.2
|
||||
twilio==5.6.0
|
||||
|
||||
@ -2,26 +2,24 @@
|
||||
# This file is autogenerated by pip-compile
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --output-file requirements.txt requirements.in
|
||||
# pip-compile --output-file requirements/requirements.txt requirements/requirements.in
|
||||
#
|
||||
|
||||
# NOTE: I thought we had to pull these guys out but I can't remember why
|
||||
# and without them we get segfaults
|
||||
git+https://github.com/ansible/ansiconv.git@tower_1.0.0#egg=ansiconv
|
||||
git+https://github.com/ansible/django-qsstats-magic.git@tower_0.7.2#egg=django-qsstats-magic
|
||||
git+https://github.com/ansible/dm.xmlsec.binding.git@master#egg=dm.xmlsec.binding
|
||||
git+https://github.com/ansible/django-jsonbfield@master#egg=jsonbfield
|
||||
git+https://github.com/chrismeyersfsu/pyrax@tower#egg=pyrax
|
||||
|
||||
adal==0.4.3 # via msrestazure
|
||||
amqp==1.4.9 # via kombu
|
||||
anyjson==0.3.3 # via kombu
|
||||
apache-libcloud==1.3.0
|
||||
appdirs==1.4.0 # via os-client-config, python-ironicclient, rply
|
||||
asgi-amqp==0.3.1
|
||||
asgiref==1.0.0 # via asgi-amqp, channels, daphne
|
||||
autobahn==0.16.1 # via daphne
|
||||
attrs==16.3.0 # via service-identity
|
||||
autobahn==0.17.0 # via daphne
|
||||
azure-batch==1.0.0 # via azure
|
||||
azure-common==1.1.4 # via azure-batch, azure-mgmt-batch, azure-mgmt-compute, azure-mgmt-keyvault, azure-mgmt-logic, azure-mgmt-network, azure-mgmt-redis, azure-mgmt-resource, azure-mgmt-scheduler, azure-mgmt-storage, azure-servicebus, azure-servicemanagement-legacy, azure-storage
|
||||
azure-common[autorest]==1.1.4 # via azure-batch, azure-mgmt-batch, azure-mgmt-compute, azure-mgmt-keyvault, azure-mgmt-logic, azure-mgmt-network, azure-mgmt-redis, azure-mgmt-resource, azure-mgmt-scheduler, azure-mgmt-storage, azure-servicebus, azure-servicemanagement-legacy, azure-storage
|
||||
azure-mgmt-batch==1.0.0 # via azure-mgmt
|
||||
azure-mgmt-compute==0.30.0rc6 # via azure-mgmt
|
||||
azure-mgmt-keyvault==0.30.0rc6 # via azure-mgmt
|
||||
@ -52,9 +50,9 @@ chardet==2.3.0 # via msrest
|
||||
cliff==2.3.0 # via osc-lib, python-designateclient, python-heatclient, python-mistralclient, python-neutronclient, python-openstackclient
|
||||
cmd2==0.6.9 # via cliff
|
||||
constantly==15.1.0 # via twisted
|
||||
cryptography==1.6 # via azure-storage, pyopenssl, python-magnumclient, secretstorage
|
||||
cryptography==1.7.1 # via adal, azure-storage, pyopenssl, python-magnumclient, secretstorage
|
||||
daphne==0.15.0 # via channels
|
||||
debtcollector==1.9.0 # via oslo.config, oslo.utils, python-designateclient, python-keystoneclient, python-neutronclient
|
||||
debtcollector==1.10.0 # via oslo.config, oslo.utils, python-designateclient, python-keystoneclient, python-neutronclient
|
||||
decorator==4.0.10 # via python-magnumclient, shade
|
||||
defusedxml==0.4.1 # via python-saml
|
||||
django-auth-ldap==1.2.8
|
||||
@ -78,7 +76,7 @@ functools32==3.2.3.post2 # via jsonschema
|
||||
futures==3.0.5 # via azure-storage, python-swiftclient, requests-futures
|
||||
gevent-websocket==0.9.5
|
||||
gevent==1.1.2 # via gevent-websocket
|
||||
greenlet==0.4.10 # via gevent
|
||||
greenlet==0.4.11 # via gevent
|
||||
httplib2==0.9.2 # via twilio
|
||||
idna==2.1 # via cryptography
|
||||
incremental==16.10.1 # via twisted
|
||||
@ -100,33 +98,33 @@ jsonpatch==1.14 # via shade, warlock
|
||||
jsonpickle==0.9.3 # via asgi-amqp
|
||||
jsonpointer==1.10 # via jsonpatch
|
||||
jsonschema==2.5.1 # via python-designateclient, python-ironicclient, warlock
|
||||
keyring==10.0.2 # via msrest
|
||||
keystoneauth1==2.15.0 # via openstacksdk, os-client-config, osc-lib, python-cinderclient, python-designateclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-neutronclient, python-novaclient, python-openstackclient, python-troveclient, shade
|
||||
keyring==10.1 # via msrest, msrestazure
|
||||
keystoneauth1==2.16.0 # via openstacksdk, os-client-config, osc-lib, python-cinderclient, python-designateclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-neutronclient, python-novaclient, python-openstackclient, python-troveclient, shade
|
||||
kombu==3.0.35 # via asgi-amqp, celery
|
||||
#lxml==3.6.4
|
||||
lxml==3.7.0
|
||||
M2Crypto==0.25.1
|
||||
Markdown==2.6.7
|
||||
mock==2.0.0
|
||||
monotonic==1.2 # via oslo.utils
|
||||
more-itertools==2.3 # via irc, jaraco.functools, jaraco.itertools
|
||||
more-itertools==2.4.1 # via irc, jaraco.functools, jaraco.itertools
|
||||
msgpack-python==0.4.7 # via asgi-amqp, oslo.serialization
|
||||
msrest==0.4.4 # via azure-common, msrestazure
|
||||
msrestazure==0.4.4 # via azure-common
|
||||
msrestazure==0.4.6 # via azure-common
|
||||
munch==2.0.4 # via shade
|
||||
netaddr==0.7.18 # via oslo.config, oslo.utils, python-neutronclient
|
||||
netifaces==0.10.5 # via oslo.utils, shade
|
||||
oauthlib==2.0.1 # via python-social-auth, requests-oauthlib
|
||||
openstacksdk==0.9.10 # via python-openstackclient
|
||||
openstacksdk==0.9.11 # via python-openstackclient
|
||||
ordereddict==1.1
|
||||
os-client-config==1.24.0 # via openstacksdk, osc-lib, python-magnumclient, python-neutronclient, shade
|
||||
os-diskconfig-python-novaclient-ext==0.1.3 # via rackspace-novaclient
|
||||
os-networksv2-python-novaclient-ext==0.26 # via rackspace-novaclient
|
||||
os-virtual-interfacesv2-python-novaclient-ext==0.20 # via rackspace-novaclient
|
||||
osc-lib==1.2.0 # via python-designateclient, python-heatclient, python-ironicclient, python-mistralclient, python-neutronclient, python-openstackclient
|
||||
oslo.config==3.19.0 # via python-keystoneclient
|
||||
oslo.i18n==3.10.0 # via osc-lib, oslo.config, oslo.utils, python-cinderclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-neutronclient, python-novaclient, python-openstackclient, python-troveclient
|
||||
oslo.serialization==2.14.0 # via python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-neutronclient, python-novaclient
|
||||
oslo.utils==3.18.0 # via osc-lib, oslo.serialization, python-cinderclient, python-designateclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-mistralclient, python-neutronclient, python-novaclient, python-openstackclient, python-troveclient
|
||||
oslo.config==3.21.0 # via python-keystoneclient
|
||||
oslo.i18n==3.11.0 # via osc-lib, oslo.config, oslo.utils, python-cinderclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-neutronclient, python-novaclient, python-openstackclient, python-troveclient
|
||||
oslo.serialization==2.15.0 # via python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-neutronclient, python-novaclient
|
||||
oslo.utils==3.20.0 # via osc-lib, oslo.serialization, python-cinderclient, python-designateclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-mistralclient, python-neutronclient, python-novaclient, python-openstackclient, python-troveclient
|
||||
pbr==1.10.0 # via cliff, debtcollector, keystoneauth1, mock, openstacksdk, osc-lib, oslo.i18n, oslo.serialization, oslo.utils, positional, python-cinderclient, python-designateclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-mistralclient, python-neutronclient, python-novaclient, python-openstackclient, python-troveclient, requestsexceptions, shade, stevedore
|
||||
pexpect==3.1
|
||||
positional==1.1.1 # via keystoneauth1, python-keystoneclient
|
||||
@ -134,35 +132,36 @@ PrettyTable==0.7.2 # via cliff, python-cinderclient, python-glanceclient,
|
||||
psphere==0.5.2
|
||||
psutil==5.0.0
|
||||
psycopg2==2.6.2
|
||||
pyasn1==0.1.9 # via cryptography
|
||||
pyasn1-modules==0.0.8 # via service-identity
|
||||
pyasn1==0.1.9 # via cryptography, pyasn1-modules, service-identity
|
||||
pycparser==2.17 # via cffi
|
||||
pygerduty==0.35.1
|
||||
PyJWT==1.4.2 # via python-social-auth
|
||||
pyOpenSSL==16.2.0
|
||||
PyJWT==1.4.2 # via adal, python-social-auth
|
||||
pyOpenSSL==16.2.0 # via service-identity
|
||||
pyparsing==2.1.10 # via cliff, cmd2, oslo.utils
|
||||
pyrad==2.0 # via django-radius
|
||||
python-cinderclient==1.9.0 # via python-openstackclient, shade
|
||||
python-dateutil==2.6.0 # via azure-storage
|
||||
python-designateclient==2.3.0 # via shade
|
||||
python-dateutil==2.6.0 # via adal, azure-storage
|
||||
python-designateclient==2.4.0 # via shade
|
||||
python-glanceclient==2.5.0 # via python-openstackclient, shade
|
||||
python-heatclient==1.6.1 # via shade
|
||||
python-heatclient==1.7.0 # via shade
|
||||
python-ironicclient==1.8.0 # via shade
|
||||
python-keystoneclient==3.7.0 # via python-glanceclient, python-mistralclient, python-openstackclient, shade
|
||||
python-keystoneclient==3.8.0 # via python-glanceclient, python-mistralclient, python-openstackclient, shade
|
||||
python-ldap==2.4.28 # via django-auth-ldap
|
||||
python-logstash==0.4.6
|
||||
python-magnumclient==2.3.1 # via shade
|
||||
python-memcached==1.58
|
||||
python-mistralclient==2.1.1 # via python-troveclient
|
||||
python-mistralclient==2.1.2 # via python-troveclient
|
||||
python-neutronclient==6.0.0 # via shade
|
||||
python-novaclient==6.0.0 # via ip-associations-python-novaclient-ext, os-diskconfig-python-novaclient-ext, os-networksv2-python-novaclient-ext, os-virtual-interfacesv2-python-novaclient-ext, python-openstackclient, rackspace-auth-openstack, rackspace-novaclient, rax-default-network-flags-python-novaclient-ext, rax-scheduled-images-python-novaclient-ext, shade
|
||||
python-openid==2.2.5 # via python-social-auth
|
||||
python-openstackclient==3.4.1 # via python-ironicclient
|
||||
python-openstackclient==3.5.0 # via python-ironicclient
|
||||
python-radius==1.0
|
||||
python-saml==2.2.0
|
||||
python-social-auth==0.2.21
|
||||
python-swiftclient==3.2.0 # via python-heatclient, python-troveclient, shade
|
||||
python-troveclient==2.6.0 # via shade
|
||||
pytz==2016.7 # via babel, celery, irc, oslo.serialization, oslo.utils, tempora, twilio
|
||||
python-troveclient==2.7.0 # via shade
|
||||
pytz==2016.10 # via babel, celery, irc, oslo.serialization, oslo.utils, tempora, twilio
|
||||
PyYAML==3.12 # via cliff, djangorestframework-yaml, os-client-config, psphere, python-heatclient, python-ironicclient, python-mistralclient
|
||||
rackspace-auth-openstack==1.3 # via rackspace-novaclient
|
||||
rackspace-novaclient==2.1
|
||||
@ -171,16 +170,17 @@ rax-scheduled-images-python-novaclient-ext==0.3.1 # via rackspace-novaclient
|
||||
redbaron==0.6.2
|
||||
requests-futures==0.9.7
|
||||
requests-oauthlib==0.7.0 # via msrest, python-social-auth
|
||||
requests==2.12.1 # via azure-servicebus, azure-servicemanagement-legacy, azure-storage, keystoneauth1, msrest, python-cinderclient, python-designateclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-mistralclient, python-neutronclient, python-novaclient, python-social-auth, python-swiftclient, python-troveclient, requests-futures, requests-oauthlib, slackclient
|
||||
requests==2.11.1 # via adal, azure-servicebus, azure-servicemanagement-legacy, azure-storage, keystoneauth1, msrest, python-cinderclient, python-designateclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-mistralclient, python-neutronclient, python-novaclient, python-social-auth, python-swiftclient, python-troveclient, requests-futures, requests-oauthlib, slackclient
|
||||
requestsexceptions==1.1.3 # via os-client-config, shade
|
||||
rfc3986==0.4.1 # via oslo.config
|
||||
rply==0.7.4 # via baron
|
||||
secretstorage==2.3.1 # via keyring
|
||||
service-identity==16.0.0
|
||||
shade==1.13.1
|
||||
simplejson==3.10.0 # via osc-lib, python-cinderclient, python-neutronclient, python-novaclient, python-troveclient
|
||||
six==1.10.0 # via asgi-amqp, asgiref, autobahn, cliff, cryptography, debtcollector, django-extensions, irc, jaraco.classes, jaraco.collections, jaraco.itertools, jaraco.logging, jaraco.stream, keystoneauth1, mock, more-itertools, openstacksdk, osc-lib, oslo.config, oslo.i18n, oslo.serialization, oslo.utils, pygerduty, pyopenssl, pyrad, python-cinderclient, python-dateutil, python-designateclient, python-glanceclient, python-heatclient, python-ironicclient, python-keystoneclient, python-magnumclient, python-memcached, python-mistralclient, python-neutronclient, python-novaclient, python-openstackclient, python-social-auth, python-swiftclient, python-troveclient, shade, slackclient, stevedore, tempora, twilio, txaio, warlock, websocket-client
|
||||
slackclient==1.0.2
|
||||
stevedore==1.18.0 # via cliff, keystoneauth1, openstacksdk, osc-lib, oslo.config, python-designateclient, python-keystoneclient, python-magnumclient
|
||||
stevedore==1.19.1 # via cliff, keystoneauth1, openstacksdk, osc-lib, oslo.config, python-designateclient, python-keystoneclient, python-magnumclient
|
||||
suds==0.4 # via psphere
|
||||
tempora==1.6.1 # via irc, jaraco.logging
|
||||
twilio==5.6.0
|
||||
@ -190,10 +190,10 @@ typing==3.5.2.2 # via m2crypto
|
||||
unicodecsv==0.14.1 # via cliff
|
||||
uWSGI==2.0.14
|
||||
warlock==1.2.0 # via python-glanceclient
|
||||
websocket-client==0.37.0 # via slackclient
|
||||
websocket-client==0.40.0 # via slackclient
|
||||
wrapt==1.10.8 # via debtcollector, positional
|
||||
xmltodict==0.10.2
|
||||
zope.interface==4.3.2 # via twisted
|
||||
zope.interface==4.3.3 # via twisted
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
# setuptools # via cryptography, django-polymorphic, python-ldap, zope.interface
|
||||
|
||||
@ -10,7 +10,7 @@ ADD requirements/requirements.txt requirements/requirements_ansible.txt requirem
|
||||
RUN yum -y update && yum -y install curl epel-release
|
||||
RUN curl --silent --location https://rpm.nodesource.com/setup_6.x | bash -
|
||||
RUN yum -y localinstall http://download.postgresql.org/pub/repos/yum/9.4/redhat/rhel-6-x86_64/pgdg-centos94-9.4-3.noarch.rpm
|
||||
RUN yum -y update && yum -y install openssh-server ansible mg vim tmux git mercurial subversion python-devel python-psycopg2 make postgresql postgresql-devel nginx nodejs python-psutil libxml2-devel libxslt-devel libstdc++.so.6 gcc cyrus-sasl-devel cyrus-sasl openldap-devel libffi-devel zeromq-devel python-pip xmlsec1-devel swig krb5-devel xmlsec1-openssl xmlsec1 xmlsec1-openssl-devel libtool-ltdl-devel rabbitmq-server bubblewrap
|
||||
RUN yum -y update && yum -y install openssh-server ansible mg vim tmux git mercurial subversion python-devel python-psycopg2 make postgresql postgresql-devel nginx nodejs python-psutil libxml2-devel libxslt-devel libstdc++.so.6 gcc cyrus-sasl-devel cyrus-sasl openldap-devel libffi-devel zeromq-devel python-pip xmlsec1-devel swig krb5-devel xmlsec1-openssl xmlsec1 xmlsec1-openssl-devel libtool-ltdl-devel rabbitmq-server bubblewrap zanata-python-client gettext
|
||||
RUN pip install virtualenv
|
||||
RUN /usr/bin/ssh-keygen -q -t rsa -N "" -f /root/.ssh/id_rsa
|
||||
RUN mkdir -p /etc/tower
|
||||
|
||||
5
tools/scripts/manage_translations.py
Normal file → Executable file
5
tools/scripts/manage_translations.py
Normal file → Executable file
@ -194,9 +194,8 @@ if __name__ == "__main__":
|
||||
except OSError as e:
|
||||
if e.errno == os.errno.ENOENT:
|
||||
print('''
|
||||
You need zanata-python-client, install it.
|
||||
1. Install zanata-python-client, use
|
||||
$ dnf install zanata-python-client
|
||||
You need zanata python client, install it.
|
||||
1. Install zanta python client
|
||||
2. Create ~/.config/zanata.ini file:
|
||||
$ vim ~/.config/zanata.ini
|
||||
[servers]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user