diff --git a/Makefile b/Makefile index f748c7992b..8f97ddc066 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ ifeq ($(OFFICIAL),yes) AW_REPO_URL ?= http://releases.ansible.com/ansible-tower else RELEASE ?= $(BUILD) - AW_REPO_URL ?= http://jenkins.testing.ansible.com/ansible-tower_nightlies_RTYUIOPOIUYTYU/$(GIT_BRANCH) + AW_REPO_URL ?= http://jenkins.testing.ansible.com/ansible-tower_nightlies_f8b8c5588b2505970227a7b0900ef69040ad5a00/$(GIT_BRANCH) endif # Allow AMI license customization @@ -473,7 +473,7 @@ pylint: reports check: flake8 pep8 # pyflakes pylint -TEST_DIRS ?= awx/main/tests +TEST_DIRS ?= awx/main/tests awx/conf/tests # Run all API unit tests. test: @if [ "$(VENV_BASE)" ]; then \ @@ -485,7 +485,7 @@ test_unit: @if [ "$(VENV_BASE)" ]; then \ . $(VENV_BASE)/tower/bin/activate; \ fi; \ - py.test awx/main/tests/unit + py.test awx/main/tests/unit awx/conf/tests/unit # Run all API unit tests with coverage enabled. test_coverage: diff --git a/awx/api/generics.py b/awx/api/generics.py index 93a8d3d987..5e81ee7bdb 100644 --- a/awx/api/generics.py +++ b/awx/api/generics.py @@ -285,6 +285,10 @@ class ListAPIView(generics.ListAPIView, GenericAPIView): if name.endswith('_set'): continue fields.append('{}__search'.format(name)) + for relationship in self.model._meta.local_many_to_many: + if relationship.related_model._meta.app_label != 'main': + continue + fields.append('{}__search'.format(relationship.name)) return fields diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 0a10c8271c..faecaaa576 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1956,16 +1956,25 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO return res def validate(self, attrs): - survey_enabled = attrs.get('survey_enabled', self.instance and self.instance.survey_enabled or False) - job_type = attrs.get('job_type', self.instance and self.instance.job_type or None) - inventory = attrs.get('inventory', self.instance and self.instance.inventory or None) - project = attrs.get('project', self.instance and self.instance.project or None) + def get_field_from_model_or_attrs(fd): + return attrs.get(fd, self.instance and getattr(self.instance, fd) or None) + survey_enabled = get_field_from_model_or_attrs('survey_enabled') + job_type = get_field_from_model_or_attrs('job_type') + inventory = get_field_from_model_or_attrs('inventory') + credential = get_field_from_model_or_attrs('credential') + project = get_field_from_model_or_attrs('project') + + prompting_error_message = _("Must either set a default value or ask to prompt on launch.") if job_type == "scan": if inventory is None or attrs.get('ask_inventory_on_launch', False): raise serializers.ValidationError({'inventory': _('Scan jobs must be assigned a fixed inventory.')}) elif project is None: raise serializers.ValidationError({'project': _("Job types 'run' and 'check' must have assigned a project.")}) + elif credential is None and not get_field_from_model_or_attrs('ask_credential_on_launch'): + raise serializers.ValidationError({'credential': prompting_error_message}) + elif inventory is None and not get_field_from_model_or_attrs('ask_inventory_on_launch'): + raise serializers.ValidationError({'inventory': prompting_error_message}) if survey_enabled and job_type == PERM_INVENTORY_SCAN: raise serializers.ValidationError({'survey_enabled': _('Survey Enabled cannot be used with scan jobs.')}) @@ -2964,6 +2973,10 @@ class ActivityStreamSerializer(BaseSerializer): changes = serializers.SerializerMethodField() object_association = serializers.SerializerMethodField() + # Needed related fields that are not in the default summary fields + extra_listing = [ + ('workflow_job_template_node', ('id', 'unified_job_template_id')) + ] class Meta: model = ActivityStream @@ -3005,7 +3018,7 @@ class ActivityStreamSerializer(BaseSerializer): rel = {} if obj.actor is not None: rel['actor'] = reverse('api:user_detail', args=(obj.actor.pk,)) - for fk, __ in SUMMARIZABLE_FK_FIELDS.items(): + for fk, __ in SUMMARIZABLE_FK_FIELDS.items() + self.extra_listing: if not hasattr(obj, fk): continue allm2m = getattr(obj, fk).all() @@ -3027,7 +3040,7 @@ class ActivityStreamSerializer(BaseSerializer): def get_summary_fields(self, obj): summary_fields = OrderedDict() - for fk, related_fields in SUMMARIZABLE_FK_FIELDS.items(): + for fk, related_fields in SUMMARIZABLE_FK_FIELDS.items() + self.extra_listing: try: if not hasattr(obj, fk): continue diff --git a/awx/api/views.py b/awx/api/views.py index f36404d710..2182358999 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -3108,7 +3108,7 @@ class WorkflowJobTemplateActivityStreamList(WorkflowsEnforcementMixin, ActivityS self.check_parent_access(parent) qs = self.request.user.get_queryset(self.model) return qs.filter(Q(workflow_job_template=parent) | - Q(workflow_job_template_node__workflow_job_template=parent)) + Q(workflow_job_template_node__workflow_job_template=parent)).distinct() class WorkflowJobList(WorkflowsEnforcementMixin, ListCreateAPIView): @@ -3475,6 +3475,13 @@ class HostJobEventsList(BaseJobEventsList): parent_model = Host + def get_queryset(self): + parent_obj = self.get_parent_object() + self.check_parent_access(parent_obj) + qs = self.request.user.get_queryset(self.model).filter( + Q(host=parent_obj) | Q(hosts=parent_obj)).distinct() + return qs + class GroupJobEventsList(BaseJobEventsList): diff --git a/awx/conf/apps.py b/awx/conf/apps.py index 6e09545236..9ae459fb35 100644 --- a/awx/conf/apps.py +++ b/awx/conf/apps.py @@ -22,4 +22,3 @@ class ConfConfig(AppConfig): if 'http_receiver' not in LOGGING_DICT['loggers']['awx']['handlers']: LOGGING_DICT['loggers']['awx']['handlers'] += ['http_receiver'] configure_logging(settings.LOGGING_CONFIG, LOGGING_DICT) - # checks.register(SettingsWrapper._check_settings) diff --git a/awx/conf/registry.py b/awx/conf/registry.py index 2534e238c0..dd4fdb7e6a 100644 --- a/awx/conf/registry.py +++ b/awx/conf/registry.py @@ -18,9 +18,18 @@ __all__ = ['settings_registry'] class SettingsRegistry(object): """Registry of all API-configurable settings and categories.""" - def __init__(self): + def __init__(self, settings=None): + """ + :param settings: a ``django.conf.LazySettings`` object used to lookup + file-based field values (e.g., ``local_settings.py`` + and ``/etc/tower/conf.d/example.py``). If unspecified, + defaults to ``django.conf.settings``. + """ + if settings is None: + from django.conf import settings self._registry = OrderedDict() self._dependent_settings = {} + self.settings = settings def register(self, setting, **kwargs): if setting in self._registry: @@ -94,7 +103,6 @@ class SettingsRegistry(object): return bool(self._registry.get(setting, {}).get('encrypted', False)) def get_setting_field(self, setting, mixin_class=None, for_user=False, **kwargs): - from django.conf import settings from rest_framework.fields import empty field_kwargs = {} field_kwargs.update(self._registry[setting]) @@ -124,12 +132,12 @@ class SettingsRegistry(object): original_field_instance = original_field_class(**field_kwargs) if category_slug == 'user' and for_user: try: - field_instance.default = original_field_instance.to_representation(getattr(settings, setting)) + field_instance.default = original_field_instance.to_representation(getattr(self.settings, setting)) except: logger.warning('Unable to retrieve default value for user setting "%s".', setting, exc_info=True) - elif not field_instance.read_only or field_instance.default is empty: + elif not field_instance.read_only or field_instance.default is empty or not field_instance.default: try: - field_instance.default = original_field_instance.to_representation(settings._awx_conf_settings._get_default(setting)) + field_instance.default = original_field_instance.to_representation(self.settings._awx_conf_settings._get_default(setting)) except AttributeError: pass except: diff --git a/awx/conf/settings.py b/awx/conf/settings.py index d5e379ba9f..fefca9d94a 100644 --- a/awx/conf/settings.py +++ b/awx/conf/settings.py @@ -7,8 +7,7 @@ import time # Django from django.conf import settings, UserSettingsHolder -from django.core.cache import cache -from django.core import checks +from django.core.cache import cache as django_cache from django.core.exceptions import ImproperlyConfigured from django.db import ProgrammingError, OperationalError @@ -65,35 +64,46 @@ def _log_database_error(): class SettingsWrapper(UserSettingsHolder): @classmethod - def initialize(cls): + def initialize(cls, cache=None, registry=None): + """ + Used to initialize and wrap the Django settings context. + + :param cache: the Django cache backend to use for caching setting + values. ``django.core.cache`` is used by default. + :param registry: the settings registry instance used. The global + ``awx.conf.settings_registry`` is used by default. + """ if not getattr(settings, '_awx_conf_settings', False): - settings_wrapper = cls(settings._wrapped) + settings_wrapper = cls( + settings._wrapped, + cache=cache or django_cache, + registry=registry or settings_registry + ) settings._wrapped = settings_wrapper - @classmethod - def _check_settings(cls, app_configs, **kwargs): - errors = [] - # FIXME: Warn if database not available! - for setting in Setting.objects.filter(key__in=settings_registry.get_registered_settings(), user__isnull=True): - field = settings_registry.get_setting_field(setting.key) - try: - field.to_internal_value(setting.value) - except Exception as e: - errors.append(checks.Error(str(e))) - return errors + def __init__(self, default_settings, cache, registry): + """ + This constructor is generally not called directly, but by + ``SettingsWrapper.initialize`` at app startup time when settings are + parsed. + """ - def __init__(self, default_settings): + # These values have to be stored via self.__dict__ in this way to get + # around the magic __setattr__ method on this class (which is used to + # store API-assigned settings in the database). self.__dict__['default_settings'] = default_settings 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 + self.__dict__['cache'] = cache + self.__dict__['registry'] = registry def _get_supported_settings(self): - return settings_registry.get_registered_settings() + return self.registry.get_registered_settings() def _get_writeable_settings(self): - return settings_registry.get_registered_settings(read_only=False) + return self.registry.get_registered_settings(read_only=False) def _get_cache_value(self, value): if value is None: @@ -124,11 +134,11 @@ class SettingsWrapper(UserSettingsHolder): 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.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: + if self.cache.get('_awx_conf_preload_expires', empty) is not empty: return # Initialize all database-configurable settings with a marker value so # to indicate from the cache that the setting is not configured without @@ -138,7 +148,7 @@ class SettingsWrapper(UserSettingsHolder): for setting in Setting.objects.filter(key__in=settings_to_cache.keys(), user__isnull=True).order_by('pk'): if settings_to_cache[setting.key] != SETTING_CACHE_NOTSET: continue - if settings_registry.is_setting_encrypted(setting.key): + if self.registry.is_setting_encrypted(setting.key): value = decrypt_field(setting, 'value') else: value = setting.value @@ -148,7 +158,7 @@ class SettingsWrapper(UserSettingsHolder): for key, value in settings_to_cache.items(): if value != SETTING_CACHE_NOTSET: continue - field = settings_registry.get_setting_field(key) + field = self.registry.get_setting_field(key) try: settings_to_cache[key] = self._get_cache_value(field.get_default()) except SkipField: @@ -157,13 +167,13 @@ class SettingsWrapper(UserSettingsHolder): settings_to_cache = dict([(Setting.get_cache_key(k), v) for k, v in settings_to_cache.items()]) settings_to_cache['_awx_conf_preload_expires'] = self._awx_conf_preload_expires logger.debug('cache set_many(%r, %r)', settings_to_cache, SETTING_CACHE_TIMEOUT) - cache.set_many(settings_to_cache, SETTING_CACHE_TIMEOUT) + self.cache.set_many(settings_to_cache, SETTING_CACHE_TIMEOUT) def _get_local(self, name): self._preload_cache() cache_key = Setting.get_cache_key(name) try: - cache_value = cache.get(cache_key, empty) + cache_value = self.cache.get(cache_key, empty) except ValueError: cache_value = empty logger.debug('cache get(%r, %r) -> %r', cache_key, empty, cache_value) @@ -177,7 +187,7 @@ class SettingsWrapper(UserSettingsHolder): value = {} else: value = cache_value - field = settings_registry.get_setting_field(name) + field = self.registry.get_setting_field(name) if value is empty: setting = None if not field.read_only: @@ -198,8 +208,10 @@ class SettingsWrapper(UserSettingsHolder): if value is None and SETTING_CACHE_NOTSET == SETTING_CACHE_NONE: value = SETTING_CACHE_NOTSET if cache_value != value: - logger.debug('cache set(%r, %r, %r)', cache_key, self._get_cache_value(value), SETTING_CACHE_TIMEOUT) - cache.set(cache_key, self._get_cache_value(value), SETTING_CACHE_TIMEOUT) + logger.debug('cache set(%r, %r, %r)', cache_key, + self._get_cache_value(value), + SETTING_CACHE_TIMEOUT) + self.cache.set(cache_key, self._get_cache_value(value), SETTING_CACHE_TIMEOUT) if value == SETTING_CACHE_NOTSET and not SETTING_CACHE_DEFAULTS: try: value = field.get_default() @@ -214,7 +226,9 @@ class SettingsWrapper(UserSettingsHolder): else: return field.run_validation(value) except: - logger.warning('The current value "%r" for setting "%s" is invalid.', value, name, exc_info=True) + logger.warning( + 'The current value "%r" for setting "%s" is invalid.', + value, name, exc_info=True) return empty def _get_default(self, name): @@ -234,7 +248,7 @@ class SettingsWrapper(UserSettingsHolder): return self._get_default(name) def _set_local(self, name, value): - field = settings_registry.get_setting_field(name) + field = self.registry.get_setting_field(name) if field.read_only: logger.warning('Attempt to set read only setting "%s".', name) raise ImproperlyConfigured('Setting "%s" is read only.'.format(name)) @@ -244,7 +258,8 @@ class SettingsWrapper(UserSettingsHolder): setting_value = field.run_validation(data) db_value = field.to_representation(setting_value) except Exception as e: - logger.exception('Unable to assign value "%r" to setting "%s".', value, name, exc_info=True) + logger.exception('Unable to assign value "%r" to setting "%s".', + value, name, exc_info=True) raise e setting = Setting.objects.filter(key=name, user__isnull=True).order_by('pk').first() @@ -264,7 +279,7 @@ class SettingsWrapper(UserSettingsHolder): setattr(self.default_settings, name, value) def _del_local(self, name): - field = settings_registry.get_setting_field(name) + field = self.registry.get_setting_field(name) if field.read_only: logger.warning('Attempt to delete read only setting "%s".', name) raise ImproperlyConfigured('Setting "%s" is read only.'.format(name)) @@ -282,7 +297,8 @@ class SettingsWrapper(UserSettingsHolder): def __dir__(self): keys = [] with _log_database_error(): - for setting in Setting.objects.filter(key__in=self._get_supported_settings(), user__isnull=True): + for setting in Setting.objects.filter( + key__in=self._get_supported_settings(), user__isnull=True): # Skip returning settings that have been overridden but are # considered to be "not set". if setting.value is None and SETTING_CACHE_NOTSET == SETTING_CACHE_NONE: diff --git a/awx/conf/tests/__init__.py b/awx/conf/tests/__init__.py new file mode 100644 index 0000000000..46176c348f --- /dev/null +++ b/awx/conf/tests/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2017 Ansible, Inc. +# All Rights Reserved. diff --git a/awx/conf/tests/unit/test_registry.py b/awx/conf/tests/unit/test_registry.py new file mode 100644 index 0000000000..95db1c3c73 --- /dev/null +++ b/awx/conf/tests/unit/test_registry.py @@ -0,0 +1,311 @@ +# Copyright (c) 2017 Ansible, Inc. +# All Rights Reserved. + +from uuid import uuid4 + +from django.conf import LazySettings +from django.core.cache.backends.locmem import LocMemCache +from django.core.exceptions import ImproperlyConfigured +from django.utils.translation import ugettext_lazy as _ +from rest_framework.fields import empty +import pytest + +from awx.conf import fields +from awx.conf.settings import SettingsWrapper +from awx.conf.registry import SettingsRegistry + + +@pytest.fixture() +def reg(request): + """ + This fixture initializes an awx settings registry object and passes it as + an argument into the test function. + """ + cache = LocMemCache(str(uuid4()), {}) # make a new random cache each time + settings = LazySettings() + registry = SettingsRegistry(settings) + + # @pytest.mark.readonly can be used to mark specific setting values as + # "read-only". This is analogous to manually specifying a setting on the + # filesystem (e.g., in a local_settings.py in development, or in + # /etc/tower/conf.d/.py) + defaults = request.node.get_marker('readonly') + if defaults: + settings.configure(**defaults.kwargs) + settings._wrapped = SettingsWrapper(settings._wrapped, + cache, + registry) + return registry + + +def test_simple_setting_registration(reg): + assert reg.get_registered_settings() == [] + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + ) + assert reg.get_registered_settings() == ['AWX_SOME_SETTING_ENABLED'] + + +def test_simple_setting_unregistration(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + ) + assert reg.get_registered_settings() == ['AWX_SOME_SETTING_ENABLED'] + + reg.unregister('AWX_SOME_SETTING_ENABLED') + assert reg.get_registered_settings() == [] + + +def test_duplicate_setting_registration(reg): + "ensure that settings cannot be registered twice." + with pytest.raises(ImproperlyConfigured): + for i in range(2): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + ) + + +def test_field_class_required_for_registration(reg): + "settings must specify a field class to register" + with pytest.raises(ImproperlyConfigured): + reg.register('AWX_SOME_SETTING_ENABLED') + + +def test_get_registered_settings_by_slug(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + ) + assert reg.get_registered_settings(category_slug='system') == [ + 'AWX_SOME_SETTING_ENABLED' + ] + assert reg.get_registered_settings(category_slug='other') == [] + + +def test_get_registered_read_only_settings(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system' + ) + reg.register( + 'AWX_SOME_READ_ONLY', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + read_only=True + ) + assert reg.get_registered_settings(read_only=True) ==[ + 'AWX_SOME_READ_ONLY' + ] + assert reg.get_registered_settings(read_only=False) == [ + 'AWX_SOME_SETTING_ENABLED' + ] + assert reg.get_registered_settings() == [ + 'AWX_SOME_SETTING_ENABLED', + 'AWX_SOME_READ_ONLY' + ] + + +def test_get_registered_settings_with_required_features(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + feature_required='superpowers', + ) + assert reg.get_registered_settings(features_enabled=[]) == [] + assert reg.get_registered_settings(features_enabled=['superpowers']) == [ + 'AWX_SOME_SETTING_ENABLED' + ] + + +def test_get_dependent_settings(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system' + ) + reg.register( + 'AWX_SOME_DEPENDENT_SETTING', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + depends_on=['AWX_SOME_SETTING_ENABLED'] + ) + assert reg.get_dependent_settings('AWX_SOME_SETTING_ENABLED') == set([ + 'AWX_SOME_DEPENDENT_SETTING' + ]) + + +def test_get_registered_categories(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system' + ) + reg.register( + 'AWX_SOME_OTHER_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('OtherSystem'), + category_slug='other-system' + ) + assert reg.get_registered_categories() == { + 'all': _('All'), + 'changed': _('Changed'), + 'system': _('System'), + 'other-system': _('OtherSystem'), + } + + +def test_get_registered_categories_with_required_features(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('System'), + category_slug='system', + feature_required='superpowers' + ) + reg.register( + 'AWX_SOME_OTHER_SETTING_ENABLED', + field_class=fields.BooleanField, + category=_('OtherSystem'), + category_slug='other-system', + feature_required='sortapowers' + ) + assert reg.get_registered_categories(features_enabled=[]) == { + 'all': _('All'), + 'changed': _('Changed'), + } + assert reg.get_registered_categories(features_enabled=['superpowers']) == { + 'all': _('All'), + 'changed': _('Changed'), + 'system': _('System'), + } + assert reg.get_registered_categories(features_enabled=['sortapowers']) == { + 'all': _('All'), + 'changed': _('Changed'), + 'other-system': _('OtherSystem'), + } + assert reg.get_registered_categories( + features_enabled=['superpowers', 'sortapowers'] + ) == { + 'all': _('All'), + 'changed': _('Changed'), + 'system': _('System'), + 'other-system': _('OtherSystem'), + } + + +def test_is_setting_encrypted(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + reg.register( + 'AWX_SOME_ENCRYPTED_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system', + encrypted=True + ) + assert reg.is_setting_encrypted('AWX_SOME_SETTING_ENABLED') is False + assert reg.is_setting_encrypted('AWX_SOME_ENCRYPTED_SETTING') is True + + +def test_simple_field(reg): + reg.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system', + placeholder='Example Value', + feature_required='superpowers' + ) + + field = reg.get_setting_field('AWX_SOME_SETTING') + assert isinstance(field, fields.CharField) + assert field.category == _('System') + assert field.category_slug == 'system' + assert field.default is empty + assert field.placeholder == 'Example Value' + assert field.feature_required == 'superpowers' + + +def test_field_with_custom_attribute(reg): + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category_slug='system', + ) + + field = reg.get_setting_field('AWX_SOME_SETTING_ENABLED', + category_slug='other-system') + assert field.category_slug == 'other-system' + + +def test_field_with_custom_mixin(reg): + class GreatMixin(object): + + def is_great(self): + return True + + reg.register( + 'AWX_SOME_SETTING_ENABLED', + field_class=fields.BooleanField, + category_slug='system', + ) + + field = reg.get_setting_field('AWX_SOME_SETTING_ENABLED', + mixin_class=GreatMixin) + assert isinstance(field, fields.BooleanField) + assert isinstance(field, GreatMixin) + assert field.is_great() is True + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_default_value_from_settings(reg): + reg.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system', + ) + + field = reg.get_setting_field('AWX_SOME_SETTING') + assert field.default == 'DEFAULT' + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_default_value_from_settings_with_custom_representation(reg): + class LowercaseCharField(fields.CharField): + + def to_representation(self, value): + return value.lower() + + reg.register( + 'AWX_SOME_SETTING', + field_class=LowercaseCharField, + category=_('System'), + category_slug='system', + ) + + field = reg.get_setting_field('AWX_SOME_SETTING') + assert field.default == 'default' diff --git a/awx/conf/tests/unit/test_settings.py b/awx/conf/tests/unit/test_settings.py new file mode 100644 index 0000000000..08bc1eafff --- /dev/null +++ b/awx/conf/tests/unit/test_settings.py @@ -0,0 +1,264 @@ +# Copyright (c) 2017 Ansible, Inc. +# All Rights Reserved. + +from contextlib import contextmanager +from uuid import uuid4 +import time + +from django.conf import LazySettings +from django.core.cache.backends.locmem import LocMemCache +from django.core.exceptions import ImproperlyConfigured +from django.utils.translation import ugettext_lazy as _ +from rest_framework import fields +import pytest + +from awx.conf import models +from awx.conf.settings import SettingsWrapper, SETTING_CACHE_NOTSET +from awx.conf.registry import SettingsRegistry + + +@contextmanager +def apply_patches(_patches): + [p.start() for p in _patches] + yield + [p.stop() for p in _patches] + + +@pytest.fixture() +def settings(request): + """ + This fixture initializes a Django settings object that wraps our + `awx.conf.settings.SettingsWrapper` and passes it as an argument into the + test function. + + This mimics the work done by `awx.conf.settings.SettingsWrapper.initialize` + on `django.conf.settings`. + """ + cache = LocMemCache(str(uuid4()), {}) # make a new random cache each time + settings = LazySettings() + registry = SettingsRegistry(settings) + + # @pytest.mark.readonly can be used to mark specific setting values as + # "read-only". This is analogous to manually specifying a setting on the + # filesystem (e.g., in a local_settings.py in development, or in + # /etc/tower/conf.d/.py) + readonly_marker = request.node.get_marker('readonly') + defaults = readonly_marker.kwargs if readonly_marker else {} + defaults['DEFAULTS_SNAPSHOT'] = {} + settings.configure(**defaults) + settings._wrapped = SettingsWrapper(settings._wrapped, + cache, + registry) + return settings + + +@pytest.mark.readonly(DEBUG=True) +def test_unregistered_setting(settings): + "native Django settings are not stored in DB, and aren't cached" + assert settings.DEBUG is True + assert settings.cache.get('DEBUG') is None + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_read_only_setting(settings): + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + assert settings.AWX_SOME_SETTING == 'DEFAULT' + assert len(settings.registry.get_registered_settings(read_only=False)) == 0 + settings = settings.registry.get_registered_settings(read_only=True) + assert settings == ['AWX_SOME_SETTING'] + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_read_only_setting_with_empty_default(settings): + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system', + default='', + ) + assert settings.AWX_SOME_SETTING == 'DEFAULT' + assert len(settings.registry.get_registered_settings(read_only=False)) == 0 + settings = settings.registry.get_registered_settings(read_only=True) + assert settings == ['AWX_SOME_SETTING'] + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_read_only_defaults_are_cached(settings): + "read-only settings are stored in the cache" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + assert settings.AWX_SOME_SETTING == 'DEFAULT' + assert settings.cache.get('AWX_SOME_SETTING') == 'DEFAULT' + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_cache_respects_timeout(settings): + "only preload the cache every SETTING_CACHE_TIMEOUT settings" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + + assert settings.AWX_SOME_SETTING == 'DEFAULT' + cache_expiration = settings.cache.get('_awx_conf_preload_expires') + assert cache_expiration > time.time() + + assert settings.AWX_SOME_SETTING == 'DEFAULT' + assert settings.cache.get('_awx_conf_preload_expires') == cache_expiration + + +def test_default_setting(settings, mocker): + "settings that specify a default are inserted into the cache" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system', + default='DEFAULT' + ) + + settings_to_cache = mocker.Mock(**{'order_by.return_value': []}) + with mocker.patch('awx.conf.models.Setting.objects.filter', return_value=settings_to_cache): + assert settings.AWX_SOME_SETTING == 'DEFAULT' + assert settings.cache.get('AWX_SOME_SETTING') == 'DEFAULT' + + +def test_empty_setting(settings, mocker): + "settings with no default and no defined value are not valid" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + + settings_to_cache = [ + mocker.Mock(**{'order_by.return_value': []}), + mocker.Mock(**{'order_by.return_value.first.return_value': None}) + ] + with mocker.patch('awx.conf.models.Setting.objects.filter', side_effect=settings_to_cache): + with pytest.raises(AttributeError): + settings.AWX_SOME_SETTING + assert settings.cache.get('AWX_SOME_SETTING') == SETTING_CACHE_NOTSET + + +def test_setting_from_db(settings, mocker): + "settings can be loaded from the database" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system', + default='DEFAULT' + ) + + settings_to_cache = [ + mocker.Mock(**{'order_by.return_value': [ + mocker.Mock(key='AWX_SOME_SETTING', value='FROM_DB') + ]}), + ] + with mocker.patch('awx.conf.models.Setting.objects.filter', side_effect=settings_to_cache): + assert settings.AWX_SOME_SETTING == 'FROM_DB' + assert settings.cache.get('AWX_SOME_SETTING') == 'FROM_DB' + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_read_only_setting_assignment(settings): + "read-only settings cannot be overwritten" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + assert settings.AWX_SOME_SETTING == 'DEFAULT' + with pytest.raises(ImproperlyConfigured): + settings.AWX_SOME_SETTING = 'CHANGED' + assert settings.AWX_SOME_SETTING == 'DEFAULT' + + +def test_db_setting_create(settings, mocker): + "settings are stored in the database when set for the first time" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + + setting_list = mocker.Mock(**{'order_by.return_value.first.return_value': None}) + with apply_patches([ + mocker.patch('awx.conf.models.Setting.objects.filter', + return_value=setting_list), + mocker.patch('awx.conf.models.Setting.objects.create', mocker.Mock()) + ]): + settings.AWX_SOME_SETTING = 'NEW-VALUE' + + models.Setting.objects.create.assert_called_with( + key='AWX_SOME_SETTING', + user=None, + value='NEW-VALUE' + ) + + +def test_db_setting_update(settings, mocker): + "settings are updated in the database when their value changes" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + + existing_setting = mocker.Mock(key='AWX_SOME_SETTING', value='FROM_DB') + setting_list = mocker.Mock(**{ + 'order_by.return_value.first.return_value': existing_setting + }) + with mocker.patch('awx.conf.models.Setting.objects.filter', return_value=setting_list): + settings.AWX_SOME_SETTING = 'NEW-VALUE' + + assert existing_setting.value == 'NEW-VALUE' + existing_setting.save.assert_called_with(update_fields=['value']) + + +def test_db_setting_deletion(settings, mocker): + "settings are auto-deleted from the database" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + + existing_setting = mocker.Mock(key='AWX_SOME_SETTING', value='FROM_DB') + with mocker.patch('awx.conf.models.Setting.objects.filter', return_value=[existing_setting]): + del settings.AWX_SOME_SETTING + + assert existing_setting.delete.call_count == 1 + + +@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT') +def test_read_only_setting_deletion(settings): + "read-only settings cannot be deleted" + settings.registry.register( + 'AWX_SOME_SETTING', + field_class=fields.CharField, + category=_('System'), + category_slug='system' + ) + assert settings.AWX_SOME_SETTING == 'DEFAULT' + with pytest.raises(ImproperlyConfigured): + del settings.AWX_SOME_SETTING + assert settings.AWX_SOME_SETTING == 'DEFAULT' diff --git a/awx/lib/tower_display_callback/cleanup.py b/awx/lib/tower_display_callback/cleanup.py index ad99fb20bb..8926e54f72 100644 --- a/awx/lib/tower_display_callback/cleanup.py +++ b/awx/lib/tower_display_callback/cleanup.py @@ -71,7 +71,10 @@ def terminate_ssh_control_masters(): # Terminate then kill control master processes. Workaround older # version of psutil that may not have wait_procs implemented. for proc in ssh_cm_procs: - proc.terminate() + try: + proc.terminate() + except psutil.NoSuchProcess: + continue procs_gone, procs_alive = psutil.wait_procs(ssh_cm_procs, timeout=5) for proc in procs_alive: proc.kill() diff --git a/awx/locale/django.pot b/awx/locale/django.pot index ebfd9bcb4c..9a5f1ab583 100644 --- a/awx/locale/django.pot +++ b/awx/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-01-27 17:35+0000\n" +"POT-Creation-Date: 2017-01-30 03:44-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,1029 +17,1030 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: api/authentication.py:67 +#: awx/api/authentication.py:67 msgid "Invalid token header. No credentials provided." msgstr "" -#: api/authentication.py:70 +#: awx/api/authentication.py:70 msgid "Invalid token header. Token string should not contain spaces." msgstr "" -#: api/authentication.py:105 +#: awx/api/authentication.py:105 msgid "User inactive or deleted" msgstr "" -#: api/authentication.py:161 +#: awx/api/authentication.py:161 msgid "Invalid task token" msgstr "" -#: api/conf.py:12 +#: awx/api/conf.py:12 msgid "Idle Time Force Log Out" msgstr "" -#: api/conf.py:13 +#: awx/api/conf.py:13 msgid "" "Number of seconds that a user is inactive before they will need to login " "again." msgstr "" -#: api/conf.py:14 api/conf.py:24 api/conf.py:33 sso/conf.py:124 -#: sso/conf.py:135 sso/conf.py:147 sso/conf.py:162 +#: awx/api/conf.py:14 awx/api/conf.py:24 awx/api/conf.py:33 awx/sso/conf.py:124 +#: awx/sso/conf.py:135 awx/sso/conf.py:147 awx/sso/conf.py:162 msgid "Authentication" msgstr "" -#: api/conf.py:22 +#: awx/api/conf.py:22 msgid "Maximum number of simultaneous logins" msgstr "" -#: api/conf.py:23 +#: awx/api/conf.py:23 msgid "" "Maximum number of simultaneous logins a user may have. To disable enter -1." msgstr "" -#: api/conf.py:31 +#: awx/api/conf.py:31 msgid "Enable HTTP Basic Auth" msgstr "" -#: api/conf.py:32 +#: awx/api/conf.py:32 msgid "Enable HTTP Basic Auth for the API Browser." msgstr "" -#: api/generics.py:462 +#: awx/api/generics.py:462 msgid "\"id\" is required to disassociate" msgstr "" -#: api/metadata.py:50 +#: awx/api/metadata.py:50 msgid "Database ID for this {}." msgstr "" -#: api/metadata.py:51 +#: awx/api/metadata.py:51 msgid "Name of this {}." msgstr "" -#: api/metadata.py:52 +#: awx/api/metadata.py:52 msgid "Optional description of this {}." msgstr "" -#: api/metadata.py:53 +#: awx/api/metadata.py:53 msgid "Data type for this {}." msgstr "" -#: api/metadata.py:54 +#: awx/api/metadata.py:54 msgid "URL for this {}." msgstr "" -#: api/metadata.py:55 +#: awx/api/metadata.py:55 msgid "Data structure with URLs of related resources." msgstr "" -#: api/metadata.py:56 +#: awx/api/metadata.py:56 msgid "Data structure with name/description for related resources." msgstr "" -#: api/metadata.py:57 +#: awx/api/metadata.py:57 msgid "Timestamp when this {} was created." msgstr "" -#: api/metadata.py:58 +#: awx/api/metadata.py:58 msgid "Timestamp when this {} was last modified." msgstr "" -#: api/parsers.py:31 +#: awx/api/parsers.py:31 #, python-format msgid "JSON parse error - %s" msgstr "" -#: api/serializers.py:248 +#: awx/api/serializers.py:250 msgid "Playbook Run" msgstr "" -#: api/serializers.py:249 +#: awx/api/serializers.py:251 msgid "Command" msgstr "" -#: api/serializers.py:250 +#: awx/api/serializers.py:252 msgid "SCM Update" msgstr "" -#: api/serializers.py:251 +#: awx/api/serializers.py:253 msgid "Inventory Sync" msgstr "" -#: api/serializers.py:252 +#: awx/api/serializers.py:254 msgid "Management Job" msgstr "" -#: api/serializers.py:253 +#: awx/api/serializers.py:255 msgid "Workflow Job" msgstr "" -#: api/serializers.py:254 +#: awx/api/serializers.py:256 msgid "Workflow Template" msgstr "" -#: api/serializers.py:656 api/serializers.py:714 api/views.py:3805 +#: awx/api/serializers.py:658 awx/api/serializers.py:716 awx/api/views.py:3810 #, python-format msgid "" "Standard Output too large to display (%(text_size)d bytes), only download " "supported for sizes over %(supported_size)d bytes" msgstr "" -#: api/serializers.py:729 +#: awx/api/serializers.py:731 msgid "Write-only field used to change the password." msgstr "" -#: api/serializers.py:731 +#: awx/api/serializers.py:733 msgid "Set if the account is managed by an external service" msgstr "" -#: api/serializers.py:755 +#: awx/api/serializers.py:757 msgid "Password required for new User." msgstr "" -#: api/serializers.py:839 +#: awx/api/serializers.py:841 #, python-format msgid "Unable to change %s on user managed by LDAP." msgstr "" -#: api/serializers.py:991 +#: awx/api/serializers.py:993 msgid "Organization is missing" msgstr "" -#: api/serializers.py:997 +#: awx/api/serializers.py:999 msgid "Array of playbooks available within this project." msgstr "" -#: api/serializers.py:1179 +#: awx/api/serializers.py:1181 #, python-format msgid "Invalid port specification: %s" msgstr "" -#: api/serializers.py:1207 main/validators.py:193 +#: awx/api/serializers.py:1209 awx/main/validators.py:193 msgid "Must be valid JSON or YAML." msgstr "" -#: api/serializers.py:1264 +#: awx/api/serializers.py:1266 msgid "Invalid group name." msgstr "" -#: api/serializers.py:1339 +#: awx/api/serializers.py:1341 msgid "" "Script must begin with a hashbang sequence: i.e.... #!/usr/bin/env python" msgstr "" -#: api/serializers.py:1392 +#: awx/api/serializers.py:1394 msgid "If 'source' is 'custom', 'source_script' must be provided." msgstr "" -#: api/serializers.py:1396 +#: awx/api/serializers.py:1398 msgid "" "The 'source_script' does not belong to the same organization as the " "inventory." msgstr "" -#: api/serializers.py:1398 +#: awx/api/serializers.py:1400 msgid "'source_script' doesn't exist." msgstr "" -#: api/serializers.py:1757 +#: awx/api/serializers.py:1759 msgid "" "Write-only field used to add user to owner role. If provided, do not give " "either team or organization. Only valid for creation." msgstr "" -#: api/serializers.py:1762 +#: awx/api/serializers.py:1764 msgid "" "Write-only field used to add team to owner role. If provided, do not give " "either user or organization. Only valid for creation." msgstr "" -#: api/serializers.py:1767 +#: awx/api/serializers.py:1769 msgid "" "Inherit permissions from organization roles. If provided on creation, do not " "give either user or team." msgstr "" -#: api/serializers.py:1783 +#: awx/api/serializers.py:1785 msgid "Missing 'user', 'team', or 'organization'." msgstr "" -#: api/serializers.py:1796 +#: awx/api/serializers.py:1798 msgid "" "Credential organization must be set and match before assigning to a team" msgstr "" -#: api/serializers.py:1888 +#: awx/api/serializers.py:1890 msgid "This field is required." msgstr "" -#: api/serializers.py:1890 api/serializers.py:1892 +#: awx/api/serializers.py:1892 awx/api/serializers.py:1894 msgid "Playbook not found for project." msgstr "" -#: api/serializers.py:1894 +#: awx/api/serializers.py:1896 msgid "Must select playbook for project." msgstr "" -#: api/serializers.py:1958 main/models/jobs.py:278 +#: awx/api/serializers.py:1960 awx/main/models/jobs.py:278 msgid "Scan jobs must be assigned a fixed inventory." msgstr "" -#: api/serializers.py:1960 main/models/jobs.py:281 +#: awx/api/serializers.py:1962 awx/main/models/jobs.py:281 msgid "Job types 'run' and 'check' must have assigned a project." msgstr "" -#: api/serializers.py:1963 +#: awx/api/serializers.py:1965 msgid "Survey Enabled cannot be used with scan jobs." msgstr "" -#: api/serializers.py:2023 +#: awx/api/serializers.py:2025 msgid "Invalid job template." msgstr "" -#: api/serializers.py:2108 +#: awx/api/serializers.py:2110 msgid "Credential not found or deleted." msgstr "" -#: api/serializers.py:2110 +#: awx/api/serializers.py:2112 msgid "Job Template Project is missing or undefined." msgstr "" -#: api/serializers.py:2112 +#: awx/api/serializers.py:2114 msgid "Job Template Inventory is missing or undefined." msgstr "" -#: api/serializers.py:2397 +#: awx/api/serializers.py:2399 #, python-format msgid "%(job_type)s is not a valid job type. The choices are %(choices)s." msgstr "" -#: api/serializers.py:2402 +#: awx/api/serializers.py:2404 msgid "Workflow job template is missing during creation." msgstr "" -#: api/serializers.py:2407 +#: awx/api/serializers.py:2409 #, python-format msgid "Cannot nest a %s inside a WorkflowJobTemplate" msgstr "" -#: api/serializers.py:2645 +#: awx/api/serializers.py:2647 #, python-format msgid "Job Template '%s' is missing or undefined." msgstr "" -#: api/serializers.py:2671 +#: awx/api/serializers.py:2673 msgid "Must be a valid JSON or YAML dictionary." msgstr "" -#: api/serializers.py:2813 +#: awx/api/serializers.py:2815 msgid "" "Missing required fields for Notification Configuration: notification_type" msgstr "" -#: api/serializers.py:2836 +#: awx/api/serializers.py:2838 msgid "No values specified for field '{}'" msgstr "" -#: api/serializers.py:2841 +#: awx/api/serializers.py:2843 msgid "Missing required fields for Notification Configuration: {}." msgstr "" -#: api/serializers.py:2844 +#: awx/api/serializers.py:2846 msgid "Configuration field '{}' incorrect type, expected {}." msgstr "" -#: api/serializers.py:2897 +#: awx/api/serializers.py:2899 msgid "Inventory Source must be a cloud resource." msgstr "" -#: api/serializers.py:2899 +#: awx/api/serializers.py:2901 msgid "Manual Project can not have a schedule set." msgstr "" -#: api/serializers.py:2921 +#: awx/api/serializers.py:2923 msgid "DTSTART required in rrule. Value should match: DTSTART:YYYYMMDDTHHMMSSZ" msgstr "" -#: api/serializers.py:2923 +#: awx/api/serializers.py:2925 msgid "Multiple DTSTART is not supported." msgstr "" -#: api/serializers.py:2925 +#: awx/api/serializers.py:2927 msgid "RRULE require in rrule." msgstr "" -#: api/serializers.py:2927 +#: awx/api/serializers.py:2929 msgid "Multiple RRULE is not supported." msgstr "" -#: api/serializers.py:2929 +#: awx/api/serializers.py:2931 msgid "INTERVAL required in rrule." msgstr "" -#: api/serializers.py:2931 +#: awx/api/serializers.py:2933 msgid "TZID is not supported." msgstr "" -#: api/serializers.py:2933 +#: awx/api/serializers.py:2935 msgid "SECONDLY is not supported." msgstr "" -#: api/serializers.py:2935 +#: awx/api/serializers.py:2937 msgid "Multiple BYMONTHDAYs not supported." msgstr "" -#: api/serializers.py:2937 +#: awx/api/serializers.py:2939 msgid "Multiple BYMONTHs not supported." msgstr "" -#: api/serializers.py:2939 +#: awx/api/serializers.py:2941 msgid "BYDAY with numeric prefix not supported." msgstr "" -#: api/serializers.py:2941 +#: awx/api/serializers.py:2943 msgid "BYYEARDAY not supported." msgstr "" -#: api/serializers.py:2943 +#: awx/api/serializers.py:2945 msgid "BYWEEKNO not supported." msgstr "" -#: api/serializers.py:2947 +#: awx/api/serializers.py:2949 msgid "COUNT > 999 is unsupported." msgstr "" -#: api/serializers.py:2951 +#: awx/api/serializers.py:2953 msgid "rrule parsing failed validation." msgstr "" -#: api/serializers.py:2969 +#: awx/api/serializers.py:2971 msgid "" "A summary of the new and changed values when an object is created, updated, " "or deleted" msgstr "" -#: api/serializers.py:2971 +#: awx/api/serializers.py:2973 msgid "" "For create, update, and delete events this is the object type that was " "affected. For associate and disassociate events this is the object type " "associated or disassociated with object2." msgstr "" -#: api/serializers.py:2974 +#: awx/api/serializers.py:2976 msgid "" "Unpopulated for create, update, and delete events. For associate and " "disassociate events this is the object type that object1 is being associated " "with." msgstr "" -#: api/serializers.py:2977 +#: awx/api/serializers.py:2979 msgid "The action taken with respect to the given object(s)." msgstr "" -#: api/serializers.py:3077 +#: awx/api/serializers.py:3086 msgid "Unable to login with provided credentials." msgstr "" -#: api/serializers.py:3079 +#: awx/api/serializers.py:3088 msgid "Must include \"username\" and \"password\"." msgstr "" -#: api/views.py:99 +#: awx/api/views.py:99 msgid "Your license does not allow use of the activity stream." msgstr "" -#: api/views.py:109 +#: awx/api/views.py:109 msgid "Your license does not permit use of system tracking." msgstr "" -#: api/views.py:119 +#: awx/api/views.py:119 msgid "Your license does not allow use of workflows." msgstr "" -#: api/views.py:127 templates/rest_framework/api.html:28 +#: awx/api/views.py:127 awx/templates/rest_framework/api.html:28 msgid "REST API" msgstr "" -#: api/views.py:134 templates/rest_framework/api.html:4 +#: awx/api/views.py:134 awx/templates/rest_framework/api.html:4 msgid "Ansible Tower REST API" msgstr "" -#: api/views.py:150 +#: awx/api/views.py:150 msgid "Version 1" msgstr "" -#: api/views.py:201 +#: awx/api/views.py:201 msgid "Ping" msgstr "" -#: api/views.py:230 conf/apps.py:12 +#: awx/api/views.py:230 awx/conf/apps.py:12 msgid "Configuration" msgstr "" -#: api/views.py:283 +#: awx/api/views.py:283 msgid "Invalid license data" msgstr "" -#: api/views.py:285 +#: awx/api/views.py:285 msgid "Missing 'eula_accepted' property" msgstr "" -#: api/views.py:289 +#: awx/api/views.py:289 msgid "'eula_accepted' value is invalid" msgstr "" -#: api/views.py:292 +#: awx/api/views.py:292 msgid "'eula_accepted' must be True" msgstr "" -#: api/views.py:299 +#: awx/api/views.py:299 msgid "Invalid JSON" msgstr "" -#: api/views.py:307 +#: awx/api/views.py:307 msgid "Invalid License" msgstr "" -#: api/views.py:317 +#: awx/api/views.py:317 msgid "Invalid license" msgstr "" -#: api/views.py:325 +#: awx/api/views.py:325 #, python-format msgid "Failed to remove license (%s)" msgstr "" -#: api/views.py:330 +#: awx/api/views.py:330 msgid "Dashboard" msgstr "" -#: api/views.py:436 +#: awx/api/views.py:436 msgid "Dashboard Jobs Graphs" msgstr "" -#: api/views.py:472 +#: awx/api/views.py:472 #, python-format msgid "Unknown period \"%s\"" msgstr "" -#: api/views.py:486 +#: awx/api/views.py:486 msgid "Schedules" msgstr "" -#: api/views.py:505 +#: awx/api/views.py:505 msgid "Schedule Jobs List" msgstr "" -#: api/views.py:715 +#: awx/api/views.py:715 msgid "Your Tower license only permits a single organization to exist." msgstr "" -#: api/views.py:940 api/views.py:1299 +#: awx/api/views.py:940 awx/api/views.py:1299 msgid "Role 'id' field is missing." msgstr "" -#: api/views.py:946 api/views.py:4081 +#: awx/api/views.py:946 awx/api/views.py:4086 msgid "You cannot assign an Organization role as a child role for a Team." msgstr "" -#: api/views.py:950 api/views.py:4095 +#: awx/api/views.py:950 awx/api/views.py:4100 msgid "You cannot grant system-level permissions to a team." msgstr "" -#: api/views.py:957 api/views.py:4087 +#: awx/api/views.py:957 awx/api/views.py:4092 msgid "" "You cannot grant credential access to a team when the Organization field " "isn't set, or belongs to a different organization" msgstr "" -#: api/views.py:1047 +#: awx/api/views.py:1047 msgid "Cannot delete project." msgstr "" -#: api/views.py:1076 +#: awx/api/views.py:1076 msgid "Project Schedules" msgstr "" -#: api/views.py:1180 api/views.py:2270 api/views.py:3276 +#: awx/api/views.py:1180 awx/api/views.py:2271 awx/api/views.py:3284 msgid "Cannot delete job resource when associated workflow job is running." msgstr "" -#: api/views.py:1257 +#: awx/api/views.py:1257 msgid "Me" msgstr "" -#: api/views.py:1303 api/views.py:4036 +#: awx/api/views.py:1303 awx/api/views.py:4041 msgid "You may not perform any action with your own admin_role." msgstr "" -#: api/views.py:1309 api/views.py:4040 +#: awx/api/views.py:1309 awx/api/views.py:4045 msgid "You may not change the membership of a users admin_role" msgstr "" -#: api/views.py:1314 api/views.py:4045 +#: awx/api/views.py:1314 awx/api/views.py:4050 msgid "" "You cannot grant credential access to a user not in the credentials' " "organization" msgstr "" -#: api/views.py:1318 api/views.py:4049 +#: awx/api/views.py:1318 awx/api/views.py:4054 msgid "You cannot grant private credential access to another user" msgstr "" -#: api/views.py:1416 +#: awx/api/views.py:1416 #, python-format msgid "Cannot change %s." msgstr "" -#: api/views.py:1422 +#: awx/api/views.py:1422 msgid "Cannot delete user." msgstr "" -#: api/views.py:1570 +#: awx/api/views.py:1570 msgid "Cannot delete inventory script." msgstr "" -#: api/views.py:1805 +#: awx/api/views.py:1806 msgid "Fact not found." msgstr "" -#: api/views.py:2125 +#: awx/api/views.py:2126 msgid "Inventory Source List" msgstr "" -#: api/views.py:2153 +#: awx/api/views.py:2154 msgid "Cannot delete inventory source." msgstr "" -#: api/views.py:2161 +#: awx/api/views.py:2162 msgid "Inventory Source Schedules" msgstr "" -#: api/views.py:2191 +#: awx/api/views.py:2192 msgid "Notification Templates can only be assigned when source is one of {}." msgstr "" -#: api/views.py:2402 +#: awx/api/views.py:2403 msgid "Job Template Schedules" msgstr "" -#: api/views.py:2422 api/views.py:2438 +#: awx/api/views.py:2423 awx/api/views.py:2439 msgid "Your license does not allow adding surveys." msgstr "" -#: api/views.py:2445 +#: awx/api/views.py:2446 msgid "'name' missing from survey spec." msgstr "" -#: api/views.py:2447 +#: awx/api/views.py:2448 msgid "'description' missing from survey spec." msgstr "" -#: api/views.py:2449 +#: awx/api/views.py:2450 msgid "'spec' missing from survey spec." msgstr "" -#: api/views.py:2451 +#: awx/api/views.py:2452 msgid "'spec' must be a list of items." msgstr "" -#: api/views.py:2453 +#: awx/api/views.py:2454 msgid "'spec' doesn't contain any items." msgstr "" -#: api/views.py:2459 +#: awx/api/views.py:2460 #, python-format msgid "Survey question %s is not a json object." msgstr "" -#: api/views.py:2461 +#: awx/api/views.py:2462 #, python-format msgid "'type' missing from survey question %s." msgstr "" -#: api/views.py:2463 +#: awx/api/views.py:2464 #, python-format msgid "'question_name' missing from survey question %s." msgstr "" -#: api/views.py:2465 +#: awx/api/views.py:2466 #, python-format msgid "'variable' missing from survey question %s." msgstr "" -#: api/views.py:2467 +#: awx/api/views.py:2468 #, python-format msgid "'variable' '%(item)s' duplicated in survey question %(survey)s." msgstr "" -#: api/views.py:2472 +#: awx/api/views.py:2473 #, python-format msgid "'required' missing from survey question %s." msgstr "" -#: api/views.py:2683 +#: awx/api/views.py:2684 msgid "No matching host could be found!" msgstr "" -#: api/views.py:2686 +#: awx/api/views.py:2687 msgid "Multiple hosts matched the request!" msgstr "" -#: api/views.py:2691 +#: awx/api/views.py:2692 msgid "Cannot start automatically, user input required!" msgstr "" -#: api/views.py:2698 +#: awx/api/views.py:2699 msgid "Host callback job already pending." msgstr "" -#: api/views.py:2711 +#: awx/api/views.py:2712 msgid "Error starting job!" msgstr "" -#: api/views.py:3040 +#: awx/api/views.py:3041 msgid "Workflow Job Template Schedules" msgstr "" -#: api/views.py:3175 api/views.py:3714 +#: awx/api/views.py:3183 awx/api/views.py:3719 msgid "Superuser privileges needed." msgstr "" -#: api/views.py:3207 +#: awx/api/views.py:3215 msgid "System Job Template Schedules" msgstr "" -#: api/views.py:3399 +#: awx/api/views.py:3407 msgid "Job Host Summaries List" msgstr "" -#: api/views.py:3441 +#: awx/api/views.py:3449 msgid "Job Event Children List" msgstr "" -#: api/views.py:3450 +#: awx/api/views.py:3458 msgid "Job Event Hosts List" msgstr "" -#: api/views.py:3459 +#: awx/api/views.py:3467 msgid "Job Events List" msgstr "" -#: api/views.py:3668 +#: awx/api/views.py:3673 msgid "Ad Hoc Command Events List" msgstr "" -#: api/views.py:3862 +#: awx/api/views.py:3867 #, python-format msgid "Error generating stdout download file: %s" msgstr "" -#: api/views.py:3907 +#: awx/api/views.py:3912 msgid "Delete not allowed while there are pending notifications" msgstr "" -#: api/views.py:3914 +#: awx/api/views.py:3919 msgid "Notification Template Test" msgstr "" -#: api/views.py:4030 +#: awx/api/views.py:4035 msgid "User 'id' field is missing." msgstr "" -#: api/views.py:4073 +#: awx/api/views.py:4078 msgid "Team 'id' field is missing." msgstr "" -#: conf/conf.py:20 +#: awx/conf/conf.py:20 msgid "Bud Frogs" msgstr "" -#: conf/conf.py:21 +#: awx/conf/conf.py:21 msgid "Bunny" msgstr "" -#: conf/conf.py:22 +#: awx/conf/conf.py:22 msgid "Cheese" msgstr "" -#: conf/conf.py:23 +#: awx/conf/conf.py:23 msgid "Daemon" msgstr "" -#: conf/conf.py:24 +#: awx/conf/conf.py:24 msgid "Default Cow" msgstr "" -#: conf/conf.py:25 +#: awx/conf/conf.py:25 msgid "Dragon" msgstr "" -#: conf/conf.py:26 +#: awx/conf/conf.py:26 msgid "Elephant in Snake" msgstr "" -#: conf/conf.py:27 +#: awx/conf/conf.py:27 msgid "Elephant" msgstr "" -#: conf/conf.py:28 +#: awx/conf/conf.py:28 msgid "Eyes" msgstr "" -#: conf/conf.py:29 +#: awx/conf/conf.py:29 msgid "Hello Kitty" msgstr "" -#: conf/conf.py:30 +#: awx/conf/conf.py:30 msgid "Kitty" msgstr "" -#: conf/conf.py:31 +#: awx/conf/conf.py:31 msgid "Luke Koala" msgstr "" -#: conf/conf.py:32 +#: awx/conf/conf.py:32 msgid "Meow" msgstr "" -#: conf/conf.py:33 +#: awx/conf/conf.py:33 msgid "Milk" msgstr "" -#: conf/conf.py:34 +#: awx/conf/conf.py:34 msgid "Moofasa" msgstr "" -#: conf/conf.py:35 +#: awx/conf/conf.py:35 msgid "Moose" msgstr "" -#: conf/conf.py:36 +#: awx/conf/conf.py:36 msgid "Ren" msgstr "" -#: conf/conf.py:37 +#: awx/conf/conf.py:37 msgid "Sheep" msgstr "" -#: conf/conf.py:38 +#: awx/conf/conf.py:38 msgid "Small Cow" msgstr "" -#: conf/conf.py:39 +#: awx/conf/conf.py:39 msgid "Stegosaurus" msgstr "" -#: conf/conf.py:40 +#: awx/conf/conf.py:40 msgid "Stimpy" msgstr "" -#: conf/conf.py:41 +#: awx/conf/conf.py:41 msgid "Super Milker" msgstr "" -#: conf/conf.py:42 +#: awx/conf/conf.py:42 msgid "Three Eyes" msgstr "" -#: conf/conf.py:43 +#: awx/conf/conf.py:43 msgid "Turkey" msgstr "" -#: conf/conf.py:44 +#: awx/conf/conf.py:44 msgid "Turtle" msgstr "" -#: conf/conf.py:45 +#: awx/conf/conf.py:45 msgid "Tux" msgstr "" -#: conf/conf.py:46 +#: awx/conf/conf.py:46 msgid "Udder" msgstr "" -#: conf/conf.py:47 +#: awx/conf/conf.py:47 msgid "Vader Koala" msgstr "" -#: conf/conf.py:48 +#: awx/conf/conf.py:48 msgid "Vader" msgstr "" -#: conf/conf.py:49 +#: awx/conf/conf.py:49 msgid "WWW" msgstr "" -#: conf/conf.py:52 +#: awx/conf/conf.py:52 msgid "Cow Selection" msgstr "" -#: conf/conf.py:53 +#: awx/conf/conf.py:53 msgid "Select which cow to use with cowsay when running jobs." msgstr "" -#: conf/conf.py:54 conf/conf.py:75 +#: awx/conf/conf.py:54 awx/conf/conf.py:75 msgid "Cows" msgstr "" -#: conf/conf.py:73 +#: awx/conf/conf.py:73 msgid "Example Read-Only Setting" msgstr "" -#: conf/conf.py:74 +#: awx/conf/conf.py:74 msgid "Example setting that cannot be changed." msgstr "" -#: conf/conf.py:93 +#: awx/conf/conf.py:93 msgid "Example Setting" msgstr "" -#: conf/conf.py:94 +#: awx/conf/conf.py:94 msgid "Example setting which can be different for each user." msgstr "" -#: conf/conf.py:95 conf/registry.py:67 conf/views.py:46 +#: awx/conf/conf.py:95 awx/conf/registry.py:67 awx/conf/views.py:46 msgid "User" msgstr "" -#: conf/fields.py:38 +#: awx/conf/fields.py:38 msgid "Enter a valid URL" msgstr "" -#: conf/license.py:19 +#: awx/conf/license.py:19 msgid "Your Tower license does not allow that." msgstr "" -#: conf/management/commands/migrate_to_database_settings.py:41 +#: awx/conf/management/commands/migrate_to_database_settings.py:41 msgid "Only show which settings would be commented/migrated." msgstr "" -#: conf/management/commands/migrate_to_database_settings.py:48 +#: awx/conf/management/commands/migrate_to_database_settings.py:48 msgid "Skip over settings that would raise an error when commenting/migrating." msgstr "" -#: conf/management/commands/migrate_to_database_settings.py:55 +#: awx/conf/management/commands/migrate_to_database_settings.py:55 msgid "Skip commenting out settings in files." msgstr "" -#: conf/management/commands/migrate_to_database_settings.py:61 +#: awx/conf/management/commands/migrate_to_database_settings.py:61 msgid "Backup existing settings files with this suffix." msgstr "" -#: conf/registry.py:55 +#: awx/conf/registry.py:55 msgid "All" msgstr "" -#: conf/registry.py:56 +#: awx/conf/registry.py:56 msgid "Changed" msgstr "" -#: conf/registry.py:68 +#: awx/conf/registry.py:68 msgid "User-Defaults" msgstr "" -#: conf/views.py:38 +#: awx/conf/views.py:38 msgid "Setting Categories" msgstr "" -#: conf/views.py:61 +#: awx/conf/views.py:61 msgid "Setting Detail" msgstr "" -#: main/access.py:255 +#: awx/main/access.py:255 #, python-format msgid "Bad data found in related field %s." msgstr "" -#: main/access.py:296 +#: awx/main/access.py:296 msgid "License is missing." msgstr "" -#: main/access.py:298 +#: awx/main/access.py:298 msgid "License has expired." msgstr "" -#: main/access.py:303 +#: awx/main/access.py:306 #, python-format msgid "License count of %s instances has been reached." msgstr "" -#: main/access.py:305 +#: awx/main/access.py:308 #, python-format msgid "License count of %s instances has been exceeded." msgstr "" -#: main/access.py:307 +#: awx/main/access.py:310 msgid "Host count exceeds available instances." msgstr "" -#: main/access.py:311 +#: awx/main/access.py:314 #, python-format msgid "Feature %s is not enabled in the active license." msgstr "" -#: main/access.py:313 +#: awx/main/access.py:316 msgid "Features not found in active license." msgstr "" -#: main/access.py:511 main/access.py:578 main/access.py:698 main/access.py:961 -#: main/access.py:1200 main/access.py:1597 +#: awx/main/access.py:514 awx/main/access.py:581 awx/main/access.py:706 +#: awx/main/access.py:969 awx/main/access.py:1208 awx/main/access.py:1605 msgid "Resource is being used by running jobs" msgstr "" -#: main/access.py:622 +#: awx/main/access.py:625 msgid "Unable to change inventory on a host." msgstr "" -#: main/access.py:634 main/access.py:679 +#: awx/main/access.py:642 awx/main/access.py:687 msgid "Cannot associate two items from different inventories." msgstr "" -#: main/access.py:667 +#: awx/main/access.py:675 msgid "Unable to change inventory on a group." msgstr "" -#: main/access.py:881 +#: awx/main/access.py:889 msgid "Unable to change organization on a team." msgstr "" -#: main/access.py:894 +#: awx/main/access.py:902 msgid "The {} role cannot be assigned to a team" msgstr "" -#: main/access.py:896 +#: awx/main/access.py:904 msgid "The admin_role for a User cannot be assigned to a team" msgstr "" -#: main/access.py:1670 +#: awx/main/access.py:1678 msgid "" "You do not have permission to the workflow job resources required for " "relaunch." msgstr "" -#: main/apps.py:9 +#: awx/main/apps.py:9 msgid "Main" msgstr "" -#: main/conf.py:17 +#: awx/main/conf.py:17 msgid "Enable Activity Stream" msgstr "" -#: main/conf.py:18 +#: awx/main/conf.py:18 msgid "Enable capturing activity for the Tower activity stream." msgstr "" -#: main/conf.py:19 main/conf.py:29 main/conf.py:39 main/conf.py:48 -#: main/conf.py:60 main/conf.py:78 main/conf.py:103 +#: awx/main/conf.py:19 awx/main/conf.py:29 awx/main/conf.py:39 +#: awx/main/conf.py:48 awx/main/conf.py:60 awx/main/conf.py:78 +#: awx/main/conf.py:103 msgid "System" msgstr "" -#: main/conf.py:27 +#: awx/main/conf.py:27 msgid "Enable Activity Stream for Inventory Sync" msgstr "" -#: main/conf.py:28 +#: awx/main/conf.py:28 msgid "" "Enable capturing activity for the Tower activity stream when running " "inventory sync." msgstr "" -#: main/conf.py:37 +#: awx/main/conf.py:37 msgid "All Users Visible to Organization Admins" msgstr "" -#: main/conf.py:38 +#: awx/main/conf.py:38 msgid "" "Controls whether any Organization Admin can view all users, even those not " "associated with their Organization." msgstr "" -#: main/conf.py:46 +#: awx/main/conf.py:46 msgid "Enable Tower Administrator Alerts" msgstr "" -#: main/conf.py:47 +#: awx/main/conf.py:47 msgid "" "Allow Tower to email Admin users for system events that may require " "attention." msgstr "" -#: main/conf.py:57 +#: awx/main/conf.py:57 msgid "Base URL of the Tower host" msgstr "" -#: main/conf.py:58 +#: awx/main/conf.py:58 msgid "" "This setting is used by services like notifications to render a valid url to " "the Tower host." msgstr "" -#: main/conf.py:67 +#: awx/main/conf.py:67 msgid "Remote Host Headers" msgstr "" -#: main/conf.py:68 +#: awx/main/conf.py:68 msgid "" "HTTP headers and meta keys to search to determine remote host name or IP. " "Add additional items to this list, such as \"HTTP_X_FORWARDED_FOR\", if " @@ -1054,190 +1055,192 @@ msgid "" "REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', 'REMOTE_HOST']" msgstr "" -#: main/conf.py:99 +#: awx/main/conf.py:99 msgid "Tower License" msgstr "" -#: main/conf.py:100 +#: awx/main/conf.py:100 msgid "" "The license controls which features and functionality are enabled in Tower. " "Use /api/v1/config/ to update or change the license." msgstr "" -#: main/conf.py:110 +#: awx/main/conf.py:110 msgid "Ansible Modules Allowed for Ad Hoc Jobs" msgstr "" -#: main/conf.py:111 +#: awx/main/conf.py:111 msgid "List of modules allowed to be used by ad-hoc jobs." msgstr "" -#: main/conf.py:112 main/conf.py:121 main/conf.py:130 main/conf.py:140 -#: main/conf.py:150 main/conf.py:160 main/conf.py:170 main/conf.py:180 -#: main/conf.py:190 main/conf.py:202 main/conf.py:214 main/conf.py:226 +#: awx/main/conf.py:112 awx/main/conf.py:121 awx/main/conf.py:130 +#: awx/main/conf.py:140 awx/main/conf.py:150 awx/main/conf.py:160 +#: awx/main/conf.py:170 awx/main/conf.py:180 awx/main/conf.py:190 +#: awx/main/conf.py:202 awx/main/conf.py:214 awx/main/conf.py:226 msgid "Jobs" msgstr "" -#: main/conf.py:119 +#: awx/main/conf.py:119 msgid "Enable job isolation" msgstr "" -#: main/conf.py:120 +#: awx/main/conf.py:120 msgid "" "Isolates an Ansible job from protected parts of the Tower system to prevent " "exposing sensitive information." msgstr "" -#: main/conf.py:128 +#: awx/main/conf.py:128 msgid "Job isolation execution path" msgstr "" -#: main/conf.py:129 +#: awx/main/conf.py:129 msgid "" "Create temporary working directories for isolated jobs in this location." msgstr "" -#: main/conf.py:138 +#: awx/main/conf.py:138 msgid "Paths to hide from isolated jobs" msgstr "" -#: main/conf.py:139 +#: awx/main/conf.py:139 msgid "Additional paths to hide from isolated processes." msgstr "" -#: main/conf.py:148 +#: awx/main/conf.py:148 msgid "Paths to expose to isolated jobs" msgstr "" -#: main/conf.py:149 +#: awx/main/conf.py:149 msgid "" "Whitelist of paths that would otherwise be hidden to expose to isolated jobs." msgstr "" -#: main/conf.py:158 +#: awx/main/conf.py:158 msgid "Standard Output Maximum Display Size" msgstr "" -#: main/conf.py:159 +#: awx/main/conf.py:159 msgid "" "Maximum Size of Standard Output in bytes to display before requiring the " "output be downloaded." msgstr "" -#: main/conf.py:168 +#: awx/main/conf.py:168 msgid "Job Event Standard Output Maximum Display Size" msgstr "" -#: main/conf.py:169 +#: awx/main/conf.py:169 msgid "" "Maximum Size of Standard Output in bytes to display for a single job or ad " "hoc command event. `stdout` will end with `…` when truncated." msgstr "" -#: main/conf.py:178 +#: awx/main/conf.py:178 msgid "Maximum Scheduled Jobs" msgstr "" -#: main/conf.py:179 +#: awx/main/conf.py:179 msgid "" "Maximum number of the same job template that can be waiting to run when " "launching from a schedule before no more are created." msgstr "" -#: main/conf.py:188 +#: awx/main/conf.py:188 msgid "Ansible Callback Plugins" msgstr "" -#: main/conf.py:189 +#: awx/main/conf.py:189 msgid "" "List of paths to search for extra callback plugins to be used when running " "jobs." msgstr "" -#: main/conf.py:199 +#: awx/main/conf.py:199 msgid "Default Job Timeout" msgstr "" -#: main/conf.py:200 +#: awx/main/conf.py:200 msgid "" "Maximum time to allow jobs to run. Use value of 0 to indicate that no " "timeout should be imposed. A timeout set on an individual job template will " "override this." msgstr "" -#: main/conf.py:211 +#: awx/main/conf.py:211 msgid "Default Inventory Update Timeout" msgstr "" -#: main/conf.py:212 +#: awx/main/conf.py:212 msgid "" "Maximum time to allow inventory updates to run. Use value of 0 to indicate " "that no timeout should be imposed. A timeout set on an individual inventory " "source will override this." msgstr "" -#: main/conf.py:223 +#: awx/main/conf.py:223 msgid "Default Project Update Timeout" msgstr "" -#: main/conf.py:224 +#: awx/main/conf.py:224 msgid "" "Maximum time to allow project updates to run. Use value of 0 to indicate " "that no timeout should be imposed. A timeout set on an individual project " "will override this." msgstr "" -#: main/conf.py:234 +#: awx/main/conf.py:234 msgid "Logging Aggregator" msgstr "" -#: main/conf.py:235 +#: awx/main/conf.py:235 msgid "Hostname/IP where external logs will be sent to." msgstr "" -#: main/conf.py:236 main/conf.py:245 main/conf.py:255 main/conf.py:264 -#: main/conf.py:274 main/conf.py:288 main/conf.py:300 main/conf.py:309 +#: awx/main/conf.py:236 awx/main/conf.py:245 awx/main/conf.py:255 +#: awx/main/conf.py:264 awx/main/conf.py:274 awx/main/conf.py:288 +#: awx/main/conf.py:300 awx/main/conf.py:309 msgid "Logging" msgstr "" -#: main/conf.py:243 +#: awx/main/conf.py:243 msgid "Logging Aggregator Port" msgstr "" -#: main/conf.py:244 +#: awx/main/conf.py:244 msgid "Port on Logging Aggregator to send logs to (if required)." msgstr "" -#: main/conf.py:253 +#: awx/main/conf.py:253 msgid "Logging Aggregator Type" msgstr "" -#: main/conf.py:254 +#: awx/main/conf.py:254 msgid "Format messages for the chosen log aggregator." msgstr "" -#: main/conf.py:262 +#: awx/main/conf.py:262 msgid "Logging Aggregator Username" msgstr "" -#: main/conf.py:263 +#: awx/main/conf.py:263 msgid "Username for external log aggregator (if required)." msgstr "" -#: main/conf.py:272 +#: awx/main/conf.py:272 msgid "Logging Aggregator Password/Token" msgstr "" -#: main/conf.py:273 +#: awx/main/conf.py:273 msgid "" "Password or authentication token for external log aggregator (if required)." msgstr "" -#: main/conf.py:281 +#: awx/main/conf.py:281 msgid "Loggers to send data to the log aggregator from" msgstr "" -#: main/conf.py:282 +#: awx/main/conf.py:282 msgid "" "List of loggers that will send HTTP logs to the collector, these can include " "any or all of: \n" @@ -1247,11 +1250,11 @@ msgid "" "system_tracking - facts gathered from scan jobs." msgstr "" -#: main/conf.py:295 +#: awx/main/conf.py:295 msgid "Log System Tracking Facts Individually" msgstr "" -#: main/conf.py:296 +#: awx/main/conf.py:296 msgid "" "If set, system tracking facts will be sent for each package, service, " "orother item found in a scan, allowing for greater search query granularity. " @@ -1259,1435 +1262,1527 @@ msgid "" "efficiency in fact processing." msgstr "" -#: main/conf.py:307 +#: awx/main/conf.py:307 msgid "Enable External Logging" msgstr "" -#: main/conf.py:308 +#: awx/main/conf.py:308 msgid "Enable sending logs to external log aggregator." msgstr "" -#: main/models/activity_stream.py:22 +#: awx/main/models/activity_stream.py:22 msgid "Entity Created" msgstr "" -#: main/models/activity_stream.py:23 +#: awx/main/models/activity_stream.py:23 msgid "Entity Updated" msgstr "" -#: main/models/activity_stream.py:24 +#: awx/main/models/activity_stream.py:24 msgid "Entity Deleted" msgstr "" -#: main/models/activity_stream.py:25 +#: awx/main/models/activity_stream.py:25 msgid "Entity Associated with another Entity" msgstr "" -#: main/models/activity_stream.py:26 +#: awx/main/models/activity_stream.py:26 msgid "Entity was Disassociated with another Entity" msgstr "" -#: main/models/ad_hoc_commands.py:96 +#: awx/main/models/ad_hoc_commands.py:96 msgid "No valid inventory." msgstr "" -#: main/models/ad_hoc_commands.py:103 main/models/jobs.py:161 +#: awx/main/models/ad_hoc_commands.py:103 awx/main/models/jobs.py:161 msgid "You must provide a machine / SSH credential." msgstr "" -#: main/models/ad_hoc_commands.py:114 main/models/ad_hoc_commands.py:122 +#: awx/main/models/ad_hoc_commands.py:114 +#: awx/main/models/ad_hoc_commands.py:122 msgid "Invalid type for ad hoc command" msgstr "" -#: main/models/ad_hoc_commands.py:117 +#: awx/main/models/ad_hoc_commands.py:117 msgid "Unsupported module for ad hoc commands." msgstr "" -#: main/models/ad_hoc_commands.py:125 +#: awx/main/models/ad_hoc_commands.py:125 #, python-format msgid "No argument passed to %s module." msgstr "" -#: main/models/ad_hoc_commands.py:222 main/models/jobs.py:763 +#: awx/main/models/ad_hoc_commands.py:222 awx/main/models/jobs.py:763 msgid "Host Failed" msgstr "" -#: main/models/ad_hoc_commands.py:223 main/models/jobs.py:764 +#: awx/main/models/ad_hoc_commands.py:223 awx/main/models/jobs.py:764 msgid "Host OK" msgstr "" -#: main/models/ad_hoc_commands.py:224 main/models/jobs.py:767 +#: awx/main/models/ad_hoc_commands.py:224 awx/main/models/jobs.py:767 msgid "Host Unreachable" msgstr "" -#: main/models/ad_hoc_commands.py:229 main/models/jobs.py:766 +#: awx/main/models/ad_hoc_commands.py:229 awx/main/models/jobs.py:766 msgid "Host Skipped" msgstr "" -#: main/models/ad_hoc_commands.py:239 main/models/jobs.py:794 +#: awx/main/models/ad_hoc_commands.py:239 awx/main/models/jobs.py:794 msgid "Debug" msgstr "" -#: main/models/ad_hoc_commands.py:240 main/models/jobs.py:795 +#: awx/main/models/ad_hoc_commands.py:240 awx/main/models/jobs.py:795 msgid "Verbose" msgstr "" -#: main/models/ad_hoc_commands.py:241 main/models/jobs.py:796 +#: awx/main/models/ad_hoc_commands.py:241 awx/main/models/jobs.py:796 msgid "Deprecated" msgstr "" -#: main/models/ad_hoc_commands.py:242 main/models/jobs.py:797 +#: awx/main/models/ad_hoc_commands.py:242 awx/main/models/jobs.py:797 msgid "Warning" msgstr "" -#: main/models/ad_hoc_commands.py:243 main/models/jobs.py:798 +#: awx/main/models/ad_hoc_commands.py:243 awx/main/models/jobs.py:798 msgid "System Warning" msgstr "" -#: main/models/ad_hoc_commands.py:244 main/models/jobs.py:799 -#: main/models/unified_jobs.py:64 +#: awx/main/models/ad_hoc_commands.py:244 awx/main/models/jobs.py:799 +#: awx/main/models/unified_jobs.py:64 msgid "Error" msgstr "" -#: main/models/base.py:45 main/models/base.py:51 main/models/base.py:56 +#: awx/main/models/base.py:45 awx/main/models/base.py:51 +#: awx/main/models/base.py:56 msgid "Run" msgstr "" -#: main/models/base.py:46 main/models/base.py:52 main/models/base.py:57 +#: awx/main/models/base.py:46 awx/main/models/base.py:52 +#: awx/main/models/base.py:57 msgid "Check" msgstr "" -#: main/models/base.py:47 +#: awx/main/models/base.py:47 msgid "Scan" msgstr "" -#: main/models/base.py:61 +#: awx/main/models/base.py:61 msgid "Read Inventory" msgstr "" -#: main/models/base.py:62 +#: awx/main/models/base.py:62 msgid "Edit Inventory" msgstr "" -#: main/models/base.py:63 +#: awx/main/models/base.py:63 msgid "Administrate Inventory" msgstr "" -#: main/models/base.py:64 +#: awx/main/models/base.py:64 msgid "Deploy To Inventory" msgstr "" -#: main/models/base.py:65 +#: awx/main/models/base.py:65 msgid "Deploy To Inventory (Dry Run)" msgstr "" -#: main/models/base.py:66 +#: awx/main/models/base.py:66 msgid "Scan an Inventory" msgstr "" -#: main/models/base.py:67 +#: awx/main/models/base.py:67 msgid "Create a Job Template" msgstr "" -#: main/models/credential.py:33 +#: awx/main/models/credential.py:33 msgid "Machine" msgstr "" -#: main/models/credential.py:34 +#: awx/main/models/credential.py:34 msgid "Network" msgstr "" -#: main/models/credential.py:35 +#: awx/main/models/credential.py:35 msgid "Source Control" msgstr "" -#: main/models/credential.py:36 +#: awx/main/models/credential.py:36 msgid "Amazon Web Services" msgstr "" -#: main/models/credential.py:37 +#: awx/main/models/credential.py:37 msgid "Rackspace" msgstr "" -#: main/models/credential.py:38 main/models/inventory.py:713 +#: awx/main/models/credential.py:38 awx/main/models/inventory.py:713 msgid "VMware vCenter" msgstr "" -#: main/models/credential.py:39 main/models/inventory.py:714 +#: awx/main/models/credential.py:39 awx/main/models/inventory.py:714 msgid "Red Hat Satellite 6" msgstr "" -#: main/models/credential.py:40 main/models/inventory.py:715 +#: awx/main/models/credential.py:40 awx/main/models/inventory.py:715 msgid "Red Hat CloudForms" msgstr "" -#: main/models/credential.py:41 main/models/inventory.py:710 +#: awx/main/models/credential.py:41 awx/main/models/inventory.py:710 msgid "Google Compute Engine" msgstr "" -#: main/models/credential.py:42 main/models/inventory.py:711 +#: awx/main/models/credential.py:42 awx/main/models/inventory.py:711 msgid "Microsoft Azure Classic (deprecated)" msgstr "" -#: main/models/credential.py:43 main/models/inventory.py:712 +#: awx/main/models/credential.py:43 awx/main/models/inventory.py:712 msgid "Microsoft Azure Resource Manager" msgstr "" -#: main/models/credential.py:44 main/models/inventory.py:716 +#: awx/main/models/credential.py:44 awx/main/models/inventory.py:716 msgid "OpenStack" msgstr "" -#: main/models/credential.py:48 +#: awx/main/models/credential.py:48 msgid "None" msgstr "" -#: main/models/credential.py:49 +#: awx/main/models/credential.py:49 msgid "Sudo" msgstr "" -#: main/models/credential.py:50 +#: awx/main/models/credential.py:50 msgid "Su" msgstr "" -#: main/models/credential.py:51 +#: awx/main/models/credential.py:51 msgid "Pbrun" msgstr "" -#: main/models/credential.py:52 +#: awx/main/models/credential.py:52 msgid "Pfexec" msgstr "" -#: main/models/credential.py:53 +#: awx/main/models/credential.py:53 msgid "DZDO" msgstr "" -#: main/models/credential.py:54 +#: awx/main/models/credential.py:54 msgid "Pmrun" msgstr "" -#: main/models/credential.py:103 +#: awx/main/models/credential.py:103 msgid "Host" msgstr "" -#: main/models/credential.py:104 +#: awx/main/models/credential.py:104 msgid "The hostname or IP address to use." msgstr "" -#: main/models/credential.py:110 +#: awx/main/models/credential.py:110 msgid "Username" msgstr "" -#: main/models/credential.py:111 +#: awx/main/models/credential.py:111 msgid "Username for this credential." msgstr "" -#: main/models/credential.py:117 +#: awx/main/models/credential.py:117 msgid "Password" msgstr "" -#: main/models/credential.py:118 +#: awx/main/models/credential.py:118 msgid "" "Password for this credential (or \"ASK\" to prompt the user for machine " "credentials)." msgstr "" -#: main/models/credential.py:125 +#: awx/main/models/credential.py:125 msgid "Security Token" msgstr "" -#: main/models/credential.py:126 +#: awx/main/models/credential.py:126 msgid "Security Token for this credential" msgstr "" -#: main/models/credential.py:132 +#: awx/main/models/credential.py:132 msgid "Project" msgstr "" -#: main/models/credential.py:133 +#: awx/main/models/credential.py:133 msgid "The identifier for the project." msgstr "" -#: main/models/credential.py:139 +#: awx/main/models/credential.py:139 msgid "Domain" msgstr "" -#: main/models/credential.py:140 +#: awx/main/models/credential.py:140 msgid "The identifier for the domain." msgstr "" -#: main/models/credential.py:145 +#: awx/main/models/credential.py:145 msgid "SSH private key" msgstr "" -#: main/models/credential.py:146 +#: awx/main/models/credential.py:146 msgid "RSA or DSA private key to be used instead of password." msgstr "" -#: main/models/credential.py:152 +#: awx/main/models/credential.py:152 msgid "SSH key unlock" msgstr "" -#: main/models/credential.py:153 +#: awx/main/models/credential.py:153 msgid "" "Passphrase to unlock SSH private key if encrypted (or \"ASK\" to prompt the " "user for machine credentials)." msgstr "" -#: main/models/credential.py:161 +#: awx/main/models/credential.py:161 msgid "Privilege escalation method." msgstr "" -#: main/models/credential.py:167 +#: awx/main/models/credential.py:167 msgid "Privilege escalation username." msgstr "" -#: main/models/credential.py:173 +#: awx/main/models/credential.py:173 msgid "Password for privilege escalation method." msgstr "" -#: main/models/credential.py:179 +#: awx/main/models/credential.py:179 msgid "Vault password (or \"ASK\" to prompt the user)." msgstr "" -#: main/models/credential.py:183 +#: awx/main/models/credential.py:183 msgid "Whether to use the authorize mechanism." msgstr "" -#: main/models/credential.py:189 +#: awx/main/models/credential.py:189 msgid "Password used by the authorize mechanism." msgstr "" -#: main/models/credential.py:195 +#: awx/main/models/credential.py:195 msgid "Client Id or Application Id for the credential" msgstr "" -#: main/models/credential.py:201 +#: awx/main/models/credential.py:201 msgid "Secret Token for this credential" msgstr "" -#: main/models/credential.py:207 +#: awx/main/models/credential.py:207 msgid "Subscription identifier for this credential" msgstr "" -#: main/models/credential.py:213 +#: awx/main/models/credential.py:213 msgid "Tenant identifier for this credential" msgstr "" -#: main/models/credential.py:283 +#: awx/main/models/credential.py:283 msgid "Host required for VMware credential." msgstr "" -#: main/models/credential.py:285 +#: awx/main/models/credential.py:285 msgid "Host required for OpenStack credential." msgstr "" -#: main/models/credential.py:294 +#: awx/main/models/credential.py:294 msgid "Access key required for AWS credential." msgstr "" -#: main/models/credential.py:296 +#: awx/main/models/credential.py:296 msgid "Username required for Rackspace credential." msgstr "" -#: main/models/credential.py:299 +#: awx/main/models/credential.py:299 msgid "Username required for VMware credential." msgstr "" -#: main/models/credential.py:301 +#: awx/main/models/credential.py:301 msgid "Username required for OpenStack credential." msgstr "" -#: main/models/credential.py:307 +#: awx/main/models/credential.py:307 msgid "Secret key required for AWS credential." msgstr "" -#: main/models/credential.py:309 +#: awx/main/models/credential.py:309 msgid "API key required for Rackspace credential." msgstr "" -#: main/models/credential.py:311 +#: awx/main/models/credential.py:311 msgid "Password required for VMware credential." msgstr "" -#: main/models/credential.py:313 +#: awx/main/models/credential.py:313 msgid "Password or API key required for OpenStack credential." msgstr "" -#: main/models/credential.py:319 +#: awx/main/models/credential.py:319 msgid "Project name required for OpenStack credential." msgstr "" -#: main/models/credential.py:346 +#: awx/main/models/credential.py:346 msgid "SSH key unlock must be set when SSH key is encrypted." msgstr "" -#: main/models/credential.py:352 +#: awx/main/models/credential.py:352 msgid "Credential cannot be assigned to both a user and team." msgstr "" -#: main/models/fact.py:21 +#: awx/main/models/fact.py:21 msgid "Host for the facts that the fact scan captured." msgstr "" -#: main/models/fact.py:26 +#: awx/main/models/fact.py:26 msgid "Date and time of the corresponding fact scan gathering time." msgstr "" -#: main/models/fact.py:29 +#: awx/main/models/fact.py:29 msgid "" "Arbitrary JSON structure of module facts captured at timestamp for a single " "host." msgstr "" -#: main/models/inventory.py:45 +#: awx/main/models/inventory.py:45 msgid "inventories" msgstr "" -#: main/models/inventory.py:52 +#: awx/main/models/inventory.py:52 msgid "Organization containing this inventory." msgstr "" -#: main/models/inventory.py:58 +#: awx/main/models/inventory.py:58 msgid "Inventory variables in JSON or YAML format." msgstr "" -#: main/models/inventory.py:63 +#: awx/main/models/inventory.py:63 msgid "Flag indicating whether any hosts in this inventory have failed." msgstr "" -#: main/models/inventory.py:68 +#: awx/main/models/inventory.py:68 msgid "Total number of hosts in this inventory." msgstr "" -#: main/models/inventory.py:73 +#: awx/main/models/inventory.py:73 msgid "Number of hosts in this inventory with active failures." msgstr "" -#: main/models/inventory.py:78 +#: awx/main/models/inventory.py:78 msgid "Total number of groups in this inventory." msgstr "" -#: main/models/inventory.py:83 +#: awx/main/models/inventory.py:83 msgid "Number of groups in this inventory with active failures." msgstr "" -#: main/models/inventory.py:88 +#: awx/main/models/inventory.py:88 msgid "" "Flag indicating whether this inventory has any external inventory sources." msgstr "" -#: main/models/inventory.py:93 +#: awx/main/models/inventory.py:93 msgid "" "Total number of external inventory sources configured within this inventory." msgstr "" -#: main/models/inventory.py:98 +#: awx/main/models/inventory.py:98 msgid "Number of external inventory sources in this inventory with failures." msgstr "" -#: main/models/inventory.py:339 +#: awx/main/models/inventory.py:339 msgid "Is this host online and available for running jobs?" msgstr "" -#: main/models/inventory.py:345 +#: awx/main/models/inventory.py:345 msgid "" "The value used by the remote inventory source to uniquely identify the host" msgstr "" -#: main/models/inventory.py:350 +#: awx/main/models/inventory.py:350 msgid "Host variables in JSON or YAML format." msgstr "" -#: main/models/inventory.py:372 +#: awx/main/models/inventory.py:372 msgid "Flag indicating whether the last job failed for this host." msgstr "" -#: main/models/inventory.py:377 +#: awx/main/models/inventory.py:377 msgid "" "Flag indicating whether this host was created/updated from any external " "inventory sources." msgstr "" -#: main/models/inventory.py:383 +#: awx/main/models/inventory.py:383 msgid "Inventory source(s) that created or modified this host." msgstr "" -#: main/models/inventory.py:474 +#: awx/main/models/inventory.py:474 msgid "Group variables in JSON or YAML format." msgstr "" -#: main/models/inventory.py:480 +#: awx/main/models/inventory.py:480 msgid "Hosts associated directly with this group." msgstr "" -#: main/models/inventory.py:485 +#: awx/main/models/inventory.py:485 msgid "Total number of hosts directly or indirectly in this group." msgstr "" -#: main/models/inventory.py:490 +#: awx/main/models/inventory.py:490 msgid "Flag indicating whether this group has any hosts with active failures." msgstr "" -#: main/models/inventory.py:495 +#: awx/main/models/inventory.py:495 msgid "Number of hosts in this group with active failures." msgstr "" -#: main/models/inventory.py:500 +#: awx/main/models/inventory.py:500 msgid "Total number of child groups contained within this group." msgstr "" -#: main/models/inventory.py:505 +#: awx/main/models/inventory.py:505 msgid "Number of child groups within this group that have active failures." msgstr "" -#: main/models/inventory.py:510 +#: awx/main/models/inventory.py:510 msgid "" "Flag indicating whether this group was created/updated from any external " "inventory sources." msgstr "" -#: main/models/inventory.py:516 +#: awx/main/models/inventory.py:516 msgid "Inventory source(s) that created or modified this group." msgstr "" -#: main/models/inventory.py:706 main/models/projects.py:42 -#: main/models/unified_jobs.py:402 +#: awx/main/models/inventory.py:706 awx/main/models/projects.py:42 +#: awx/main/models/unified_jobs.py:402 msgid "Manual" msgstr "" -#: main/models/inventory.py:707 +#: awx/main/models/inventory.py:707 msgid "Local File, Directory or Script" msgstr "" -#: main/models/inventory.py:708 +#: awx/main/models/inventory.py:708 msgid "Rackspace Cloud Servers" msgstr "" -#: main/models/inventory.py:709 +#: awx/main/models/inventory.py:709 msgid "Amazon EC2" msgstr "" -#: main/models/inventory.py:717 +#: awx/main/models/inventory.py:717 msgid "Custom Script" msgstr "" -#: main/models/inventory.py:828 +#: awx/main/models/inventory.py:828 msgid "Inventory source variables in YAML or JSON format." msgstr "" -#: main/models/inventory.py:847 +#: awx/main/models/inventory.py:847 msgid "" "Comma-separated list of filter expressions (EC2 only). Hosts are imported " "when ANY of the filters match." msgstr "" -#: main/models/inventory.py:853 +#: awx/main/models/inventory.py:853 msgid "Limit groups automatically created from inventory source (EC2 only)." msgstr "" -#: main/models/inventory.py:857 +#: awx/main/models/inventory.py:857 msgid "Overwrite local groups and hosts from remote inventory source." msgstr "" -#: main/models/inventory.py:861 +#: awx/main/models/inventory.py:861 msgid "Overwrite local variables from remote inventory source." msgstr "" -#: main/models/inventory.py:893 +#: awx/main/models/inventory.py:893 msgid "Availability Zone" msgstr "" -#: main/models/inventory.py:894 +#: awx/main/models/inventory.py:894 msgid "Image ID" msgstr "" -#: main/models/inventory.py:895 +#: awx/main/models/inventory.py:895 msgid "Instance ID" msgstr "" -#: main/models/inventory.py:896 +#: awx/main/models/inventory.py:896 msgid "Instance Type" msgstr "" -#: main/models/inventory.py:897 +#: awx/main/models/inventory.py:897 msgid "Key Name" msgstr "" -#: main/models/inventory.py:898 +#: awx/main/models/inventory.py:898 msgid "Region" msgstr "" -#: main/models/inventory.py:899 +#: awx/main/models/inventory.py:899 msgid "Security Group" msgstr "" -#: main/models/inventory.py:900 +#: awx/main/models/inventory.py:900 msgid "Tags" msgstr "" -#: main/models/inventory.py:901 +#: awx/main/models/inventory.py:901 msgid "VPC ID" msgstr "" -#: main/models/inventory.py:902 +#: awx/main/models/inventory.py:902 msgid "Tag None" msgstr "" -#: main/models/inventory.py:973 +#: awx/main/models/inventory.py:973 #, python-format msgid "" "Cloud-based inventory sources (such as %s) require credentials for the " "matching cloud service." msgstr "" -#: main/models/inventory.py:980 +#: awx/main/models/inventory.py:980 msgid "Credential is required for a cloud source." msgstr "" -#: main/models/inventory.py:1005 +#: awx/main/models/inventory.py:1005 #, python-format msgid "Invalid %(source)s region: %(region)s" msgstr "" -#: main/models/inventory.py:1030 +#: awx/main/models/inventory.py:1030 #, python-format msgid "Invalid filter expression: %(filter)s" msgstr "" -#: main/models/inventory.py:1048 +#: awx/main/models/inventory.py:1048 #, python-format msgid "Invalid group by choice: %(choice)s" msgstr "" -#: main/models/inventory.py:1195 +#: awx/main/models/inventory.py:1195 #, python-format msgid "" "Unable to configure this item for cloud sync. It is already managed by %s." msgstr "" -#: main/models/inventory.py:1290 +#: awx/main/models/inventory.py:1290 msgid "Inventory script contents" msgstr "" -#: main/models/inventory.py:1295 +#: awx/main/models/inventory.py:1295 msgid "Organization owning this inventory script" msgstr "" -#: main/models/jobs.py:169 +#: awx/main/models/jobs.py:169 msgid "You must provide a network credential." msgstr "" -#: main/models/jobs.py:177 +#: awx/main/models/jobs.py:177 msgid "" "Must provide a credential for a cloud provider, such as Amazon Web Services " "or Rackspace." msgstr "" -#: main/models/jobs.py:269 +#: awx/main/models/jobs.py:269 msgid "Job Template must provide 'inventory' or allow prompting for it." msgstr "" -#: main/models/jobs.py:273 +#: awx/main/models/jobs.py:273 msgid "Job Template must provide 'credential' or allow prompting for it." msgstr "" -#: main/models/jobs.py:362 +#: awx/main/models/jobs.py:362 msgid "Cannot override job_type to or from a scan job." msgstr "" -#: main/models/jobs.py:365 +#: awx/main/models/jobs.py:365 msgid "Inventory cannot be changed at runtime for scan jobs." msgstr "" -#: main/models/jobs.py:431 main/models/projects.py:243 +#: awx/main/models/jobs.py:431 awx/main/models/projects.py:243 msgid "SCM Revision" msgstr "" -#: main/models/jobs.py:432 +#: awx/main/models/jobs.py:432 msgid "The SCM Revision from the Project used for this job, if available" msgstr "" -#: main/models/jobs.py:440 +#: awx/main/models/jobs.py:440 msgid "" "The SCM Refresh task used to make sure the playbooks were available for the " "job run" msgstr "" -#: main/models/jobs.py:662 +#: awx/main/models/jobs.py:662 msgid "job host summaries" msgstr "" -#: main/models/jobs.py:765 +#: awx/main/models/jobs.py:765 msgid "Host Failure" msgstr "" -#: main/models/jobs.py:768 main/models/jobs.py:782 +#: awx/main/models/jobs.py:768 awx/main/models/jobs.py:782 msgid "No Hosts Remaining" msgstr "" -#: main/models/jobs.py:769 +#: awx/main/models/jobs.py:769 msgid "Host Polling" msgstr "" -#: main/models/jobs.py:770 +#: awx/main/models/jobs.py:770 msgid "Host Async OK" msgstr "" -#: main/models/jobs.py:771 +#: awx/main/models/jobs.py:771 msgid "Host Async Failure" msgstr "" -#: main/models/jobs.py:772 +#: awx/main/models/jobs.py:772 msgid "Item OK" msgstr "" -#: main/models/jobs.py:773 +#: awx/main/models/jobs.py:773 msgid "Item Failed" msgstr "" -#: main/models/jobs.py:774 +#: awx/main/models/jobs.py:774 msgid "Item Skipped" msgstr "" -#: main/models/jobs.py:775 +#: awx/main/models/jobs.py:775 msgid "Host Retry" msgstr "" -#: main/models/jobs.py:777 +#: awx/main/models/jobs.py:777 msgid "File Difference" msgstr "" -#: main/models/jobs.py:778 +#: awx/main/models/jobs.py:778 msgid "Playbook Started" msgstr "" -#: main/models/jobs.py:779 +#: awx/main/models/jobs.py:779 msgid "Running Handlers" msgstr "" -#: main/models/jobs.py:780 +#: awx/main/models/jobs.py:780 msgid "Including File" msgstr "" -#: main/models/jobs.py:781 +#: awx/main/models/jobs.py:781 msgid "No Hosts Matched" msgstr "" -#: main/models/jobs.py:783 +#: awx/main/models/jobs.py:783 msgid "Task Started" msgstr "" -#: main/models/jobs.py:785 +#: awx/main/models/jobs.py:785 msgid "Variables Prompted" msgstr "" -#: main/models/jobs.py:786 +#: awx/main/models/jobs.py:786 msgid "Gathering Facts" msgstr "" -#: main/models/jobs.py:787 +#: awx/main/models/jobs.py:787 msgid "internal: on Import for Host" msgstr "" -#: main/models/jobs.py:788 +#: awx/main/models/jobs.py:788 msgid "internal: on Not Import for Host" msgstr "" -#: main/models/jobs.py:789 +#: awx/main/models/jobs.py:789 msgid "Play Started" msgstr "" -#: main/models/jobs.py:790 +#: awx/main/models/jobs.py:790 msgid "Playbook Complete" msgstr "" -#: main/models/jobs.py:1200 +#: awx/main/models/jobs.py:1200 msgid "Remove jobs older than a certain number of days" msgstr "" -#: main/models/jobs.py:1201 +#: awx/main/models/jobs.py:1201 msgid "Remove activity stream entries older than a certain number of days" msgstr "" -#: main/models/jobs.py:1202 +#: awx/main/models/jobs.py:1202 msgid "Purge and/or reduce the granularity of system tracking data" msgstr "" -#: main/models/label.py:29 +#: awx/main/models/label.py:29 msgid "Organization this label belongs to." msgstr "" -#: main/models/notifications.py:31 +#: awx/main/models/notifications.py:31 msgid "Email" msgstr "" -#: main/models/notifications.py:32 +#: awx/main/models/notifications.py:32 msgid "Slack" msgstr "" -#: main/models/notifications.py:33 +#: awx/main/models/notifications.py:33 msgid "Twilio" msgstr "" -#: main/models/notifications.py:34 +#: awx/main/models/notifications.py:34 msgid "Pagerduty" msgstr "" -#: main/models/notifications.py:35 +#: awx/main/models/notifications.py:35 msgid "HipChat" msgstr "" -#: main/models/notifications.py:36 +#: awx/main/models/notifications.py:36 msgid "Webhook" msgstr "" -#: main/models/notifications.py:37 +#: awx/main/models/notifications.py:37 msgid "IRC" msgstr "" -#: main/models/notifications.py:127 main/models/unified_jobs.py:59 +#: awx/main/models/notifications.py:127 awx/main/models/unified_jobs.py:59 msgid "Pending" msgstr "" -#: main/models/notifications.py:128 main/models/unified_jobs.py:62 +#: awx/main/models/notifications.py:128 awx/main/models/unified_jobs.py:62 msgid "Successful" msgstr "" -#: main/models/notifications.py:129 main/models/unified_jobs.py:63 +#: awx/main/models/notifications.py:129 awx/main/models/unified_jobs.py:63 msgid "Failed" msgstr "" -#: main/models/organization.py:157 +#: awx/main/models/organization.py:157 msgid "Execute Commands on the Inventory" msgstr "" -#: main/models/organization.py:211 +#: awx/main/models/organization.py:211 msgid "Token not invalidated" msgstr "" -#: main/models/organization.py:212 +#: awx/main/models/organization.py:212 msgid "Token is expired" msgstr "" -#: main/models/organization.py:213 +#: awx/main/models/organization.py:213 msgid "The maximum number of allowed sessions for this user has been exceeded." msgstr "" -#: main/models/organization.py:216 +#: awx/main/models/organization.py:216 msgid "Invalid token" msgstr "" -#: main/models/organization.py:233 +#: awx/main/models/organization.py:233 msgid "Reason the auth token was invalidated." msgstr "" -#: main/models/organization.py:272 +#: awx/main/models/organization.py:272 msgid "Invalid reason specified" msgstr "" -#: main/models/projects.py:43 +#: awx/main/models/projects.py:43 msgid "Git" msgstr "" -#: main/models/projects.py:44 +#: awx/main/models/projects.py:44 msgid "Mercurial" msgstr "" -#: main/models/projects.py:45 +#: awx/main/models/projects.py:45 msgid "Subversion" msgstr "" -#: main/models/projects.py:71 +#: awx/main/models/projects.py:71 msgid "" "Local path (relative to PROJECTS_ROOT) containing playbooks and related " "files for this project." msgstr "" -#: main/models/projects.py:80 +#: awx/main/models/projects.py:80 msgid "SCM Type" msgstr "" -#: main/models/projects.py:81 +#: awx/main/models/projects.py:81 msgid "Specifies the source control system used to store the project." msgstr "" -#: main/models/projects.py:87 +#: awx/main/models/projects.py:87 msgid "SCM URL" msgstr "" -#: main/models/projects.py:88 +#: awx/main/models/projects.py:88 msgid "The location where the project is stored." msgstr "" -#: main/models/projects.py:94 +#: awx/main/models/projects.py:94 msgid "SCM Branch" msgstr "" -#: main/models/projects.py:95 +#: awx/main/models/projects.py:95 msgid "Specific branch, tag or commit to checkout." msgstr "" -#: main/models/projects.py:99 +#: awx/main/models/projects.py:99 msgid "Discard any local changes before syncing the project." msgstr "" -#: main/models/projects.py:103 +#: awx/main/models/projects.py:103 msgid "Delete the project before syncing." msgstr "" -#: main/models/projects.py:116 +#: awx/main/models/projects.py:116 msgid "The amount of time to run before the task is canceled." msgstr "" -#: main/models/projects.py:130 +#: awx/main/models/projects.py:130 msgid "Invalid SCM URL." msgstr "" -#: main/models/projects.py:133 +#: awx/main/models/projects.py:133 msgid "SCM URL is required." msgstr "" -#: main/models/projects.py:142 +#: awx/main/models/projects.py:142 msgid "Credential kind must be 'scm'." msgstr "" -#: main/models/projects.py:157 +#: awx/main/models/projects.py:157 msgid "Invalid credential." msgstr "" -#: main/models/projects.py:229 +#: awx/main/models/projects.py:229 msgid "Update the project when a job is launched that uses the project." msgstr "" -#: main/models/projects.py:234 +#: awx/main/models/projects.py:234 msgid "" "The number of seconds after the last project update ran that a newproject " "update will be launched as a job dependency." msgstr "" -#: main/models/projects.py:244 +#: awx/main/models/projects.py:244 msgid "The last revision fetched by a project update" msgstr "" -#: main/models/projects.py:251 +#: awx/main/models/projects.py:251 msgid "Playbook Files" msgstr "" -#: main/models/projects.py:252 +#: awx/main/models/projects.py:252 msgid "List of playbooks found in the project" msgstr "" -#: main/models/rbac.py:122 +#: awx/main/models/rbac.py:37 +msgid "System Administrator" +msgstr "" + +#: awx/main/models/rbac.py:38 +msgid "System Auditor" +msgstr "" + +#: awx/main/models/rbac.py:39 +msgid "Ad Hoc" +msgstr "" + +#: awx/main/models/rbac.py:40 +msgid "Admin" +msgstr "" + +#: awx/main/models/rbac.py:41 +msgid "Auditor" +msgstr "" + +#: awx/main/models/rbac.py:42 +msgid "Execute" +msgstr "" + +#: awx/main/models/rbac.py:43 +msgid "Member" +msgstr "" + +#: awx/main/models/rbac.py:44 +msgid "Read" +msgstr "" + +#: awx/main/models/rbac.py:45 +msgid "Update" +msgstr "" + +#: awx/main/models/rbac.py:46 +msgid "Use" +msgstr "" + +#: awx/main/models/rbac.py:50 +msgid "Can manage all aspects of the system" +msgstr "" + +#: awx/main/models/rbac.py:51 +msgid "Can view all settings on the system" +msgstr "" + +#: awx/main/models/rbac.py:52 +msgid "May run ad hoc commands on an inventory" +msgstr "" + +#: awx/main/models/rbac.py:53 +#, python-format +msgid "Can manage all aspects of the %s" +msgstr "" + +#: awx/main/models/rbac.py:54 +#, python-format +msgid "Can view all settings for the %s" +msgstr "" + +#: awx/main/models/rbac.py:55 +#, python-format +msgid "May run the %s" +msgstr "" + +#: awx/main/models/rbac.py:56 +#, python-format +msgid "User is a member of the %s" +msgstr "" + +#: awx/main/models/rbac.py:57 +#, python-format +msgid "May view settings for the %s" +msgstr "" + +#: awx/main/models/rbac.py:58 +msgid "" +"May update project or inventory or group using the configured source update " +"system" +msgstr "" + +#: awx/main/models/rbac.py:59 +#, python-format +msgid "Can use the %s in a job template" +msgstr "" + +#: awx/main/models/rbac.py:123 msgid "roles" msgstr "" -#: main/models/rbac.py:438 +#: awx/main/models/rbac.py:439 msgid "role_ancestors" msgstr "" -#: main/models/schedules.py:69 +#: awx/main/models/schedules.py:69 msgid "Enables processing of this schedule by Tower." msgstr "" -#: main/models/schedules.py:75 +#: awx/main/models/schedules.py:75 msgid "The first occurrence of the schedule occurs on or after this time." msgstr "" -#: main/models/schedules.py:81 +#: awx/main/models/schedules.py:81 msgid "" "The last occurrence of the schedule occurs before this time, aftewards the " "schedule expires." msgstr "" -#: main/models/schedules.py:85 +#: awx/main/models/schedules.py:85 msgid "A value representing the schedules iCal recurrence rule." msgstr "" -#: main/models/schedules.py:91 +#: awx/main/models/schedules.py:91 msgid "The next time that the scheduled action will run." msgstr "" -#: main/models/unified_jobs.py:58 +#: awx/main/models/unified_jobs.py:58 msgid "New" msgstr "" -#: main/models/unified_jobs.py:60 +#: awx/main/models/unified_jobs.py:60 msgid "Waiting" msgstr "" -#: main/models/unified_jobs.py:61 +#: awx/main/models/unified_jobs.py:61 msgid "Running" msgstr "" -#: main/models/unified_jobs.py:65 +#: awx/main/models/unified_jobs.py:65 msgid "Canceled" msgstr "" -#: main/models/unified_jobs.py:69 +#: awx/main/models/unified_jobs.py:69 msgid "Never Updated" msgstr "" -#: main/models/unified_jobs.py:73 ui/templates/ui/index.html:85 -#: ui/templates/ui/index.html.py:104 +#: awx/main/models/unified_jobs.py:73 awx/ui/templates/ui/index.html:85 +#: awx/ui/templates/ui/index.html.py:104 msgid "OK" msgstr "" -#: main/models/unified_jobs.py:74 +#: awx/main/models/unified_jobs.py:74 msgid "Missing" msgstr "" -#: main/models/unified_jobs.py:78 +#: awx/main/models/unified_jobs.py:78 msgid "No External Source" msgstr "" -#: main/models/unified_jobs.py:85 +#: awx/main/models/unified_jobs.py:85 msgid "Updating" msgstr "" -#: main/models/unified_jobs.py:403 +#: awx/main/models/unified_jobs.py:403 msgid "Relaunch" msgstr "" -#: main/models/unified_jobs.py:404 +#: awx/main/models/unified_jobs.py:404 msgid "Callback" msgstr "" -#: main/models/unified_jobs.py:405 +#: awx/main/models/unified_jobs.py:405 msgid "Scheduled" msgstr "" -#: main/models/unified_jobs.py:406 +#: awx/main/models/unified_jobs.py:406 msgid "Dependency" msgstr "" -#: main/models/unified_jobs.py:407 +#: awx/main/models/unified_jobs.py:407 msgid "Workflow" msgstr "" -#: main/models/unified_jobs.py:408 +#: awx/main/models/unified_jobs.py:408 msgid "Sync" msgstr "" -#: main/models/unified_jobs.py:454 +#: awx/main/models/unified_jobs.py:454 msgid "The Tower node the job executed on." msgstr "" -#: main/models/unified_jobs.py:480 +#: awx/main/models/unified_jobs.py:480 msgid "The date and time the job was queued for starting." msgstr "" -#: main/models/unified_jobs.py:486 +#: awx/main/models/unified_jobs.py:486 msgid "The date and time the job finished execution." msgstr "" -#: main/models/unified_jobs.py:492 +#: awx/main/models/unified_jobs.py:492 msgid "Elapsed time in seconds that the job ran." msgstr "" -#: main/models/unified_jobs.py:514 +#: awx/main/models/unified_jobs.py:514 msgid "" "A status field to indicate the state of the job if it wasn't able to run and " "capture stdout" msgstr "" -#: main/notifications/base.py:17 main/notifications/email_backend.py:28 +#: awx/main/notifications/base.py:17 awx/main/notifications/email_backend.py:28 msgid "" "{} #{} had status {} on Ansible Tower, view details at {}\n" "\n" msgstr "" -#: main/notifications/hipchat_backend.py:46 +#: awx/main/notifications/hipchat_backend.py:46 msgid "Error sending messages: {}" msgstr "" -#: main/notifications/hipchat_backend.py:48 +#: awx/main/notifications/hipchat_backend.py:48 msgid "Error sending message to hipchat: {}" msgstr "" -#: main/notifications/irc_backend.py:54 +#: awx/main/notifications/irc_backend.py:54 msgid "Exception connecting to irc server: {}" msgstr "" -#: main/notifications/pagerduty_backend.py:39 +#: awx/main/notifications/pagerduty_backend.py:39 msgid "Exception connecting to PagerDuty: {}" msgstr "" -#: main/notifications/pagerduty_backend.py:48 -#: main/notifications/slack_backend.py:52 -#: main/notifications/twilio_backend.py:46 +#: awx/main/notifications/pagerduty_backend.py:48 +#: awx/main/notifications/slack_backend.py:52 +#: awx/main/notifications/twilio_backend.py:46 msgid "Exception sending messages: {}" msgstr "" -#: main/notifications/twilio_backend.py:36 +#: awx/main/notifications/twilio_backend.py:36 msgid "Exception connecting to Twilio: {}" msgstr "" -#: main/notifications/webhook_backend.py:38 -#: main/notifications/webhook_backend.py:40 +#: awx/main/notifications/webhook_backend.py:38 +#: awx/main/notifications/webhook_backend.py:40 msgid "Error sending notification webhook: {}" msgstr "" -#: main/scheduler/__init__.py:130 +#: awx/main/scheduler/__init__.py:130 msgid "" "Job spawned from workflow could not start because it was not in the right " "state or required manual credentials" msgstr "" -#: main/tasks.py:180 +#: awx/main/tasks.py:180 msgid "Ansible Tower host usage over 90%" msgstr "" -#: main/tasks.py:185 +#: awx/main/tasks.py:185 msgid "Ansible Tower license will expire soon" msgstr "" -#: main/tasks.py:240 +#: awx/main/tasks.py:240 msgid "status_str must be either succeeded or failed" msgstr "" -#: main/utils/common.py:89 +#: awx/main/utils/common.py:89 #, python-format msgid "Unable to convert \"%s\" to boolean" msgstr "" -#: main/utils/common.py:243 +#: awx/main/utils/common.py:243 #, python-format msgid "Unsupported SCM type \"%s\"" msgstr "" -#: main/utils/common.py:250 main/utils/common.py:262 main/utils/common.py:281 +#: awx/main/utils/common.py:250 awx/main/utils/common.py:262 +#: awx/main/utils/common.py:281 #, python-format msgid "Invalid %s URL" msgstr "" -#: main/utils/common.py:252 main/utils/common.py:290 +#: awx/main/utils/common.py:252 awx/main/utils/common.py:290 #, python-format msgid "Unsupported %s URL" msgstr "" -#: main/utils/common.py:292 +#: awx/main/utils/common.py:292 #, python-format msgid "Unsupported host \"%s\" for file:// URL" msgstr "" -#: main/utils/common.py:294 +#: awx/main/utils/common.py:294 #, python-format msgid "Host is required for %s URL" msgstr "" -#: main/utils/common.py:312 +#: awx/main/utils/common.py:312 #, python-format msgid "Username must be \"git\" for SSH access to %s." msgstr "" -#: main/utils/common.py:318 +#: awx/main/utils/common.py:318 #, python-format msgid "Username must be \"hg\" for SSH access to %s." msgstr "" -#: main/validators.py:60 +#: awx/main/validators.py:60 #, python-format msgid "Invalid certificate or key: %r..." msgstr "" -#: main/validators.py:74 +#: awx/main/validators.py:74 #, python-format msgid "Invalid private key: unsupported type \"%s\"" msgstr "" -#: main/validators.py:78 +#: awx/main/validators.py:78 #, python-format msgid "Unsupported PEM object type: \"%s\"" msgstr "" -#: main/validators.py:103 +#: awx/main/validators.py:103 msgid "Invalid base64-encoded data" msgstr "" -#: main/validators.py:122 +#: awx/main/validators.py:122 msgid "Exactly one private key is required." msgstr "" -#: main/validators.py:124 +#: awx/main/validators.py:124 msgid "At least one private key is required." msgstr "" -#: main/validators.py:126 +#: awx/main/validators.py:126 #, python-format msgid "" "At least %(min_keys)d private keys are required, only %(key_count)d provided." msgstr "" -#: main/validators.py:129 +#: awx/main/validators.py:129 #, python-format msgid "Only one private key is allowed, %(key_count)d provided." msgstr "" -#: main/validators.py:131 +#: awx/main/validators.py:131 #, python-format msgid "" "No more than %(max_keys)d private keys are allowed, %(key_count)d provided." msgstr "" -#: main/validators.py:136 +#: awx/main/validators.py:136 msgid "Exactly one certificate is required." msgstr "" -#: main/validators.py:138 +#: awx/main/validators.py:138 msgid "At least one certificate is required." msgstr "" -#: main/validators.py:140 +#: awx/main/validators.py:140 #, python-format msgid "" "At least %(min_certs)d certificates are required, only %(cert_count)d " "provided." msgstr "" -#: main/validators.py:143 +#: awx/main/validators.py:143 #, python-format msgid "Only one certificate is allowed, %(cert_count)d provided." msgstr "" -#: main/validators.py:145 +#: awx/main/validators.py:145 #, python-format msgid "" "No more than %(max_certs)d certificates are allowed, %(cert_count)d provided." msgstr "" -#: main/views.py:20 +#: awx/main/views.py:20 msgid "API Error" msgstr "" -#: main/views.py:49 +#: awx/main/views.py:49 msgid "Bad Request" msgstr "" -#: main/views.py:50 +#: awx/main/views.py:50 msgid "The request could not be understood by the server." msgstr "" -#: main/views.py:57 +#: awx/main/views.py:57 msgid "Forbidden" msgstr "" -#: main/views.py:58 +#: awx/main/views.py:58 msgid "You don't have permission to access the requested resource." msgstr "" -#: main/views.py:65 +#: awx/main/views.py:65 msgid "Not Found" msgstr "" -#: main/views.py:66 +#: awx/main/views.py:66 msgid "The requested resource could not be found." msgstr "" -#: main/views.py:73 +#: awx/main/views.py:73 msgid "Server Error" msgstr "" -#: main/views.py:74 +#: awx/main/views.py:74 msgid "A server error has occurred." msgstr "" -#: settings/defaults.py:611 +#: awx/settings/defaults.py:611 msgid "Chicago" msgstr "" -#: settings/defaults.py:612 +#: awx/settings/defaults.py:612 msgid "Dallas/Ft. Worth" msgstr "" -#: settings/defaults.py:613 +#: awx/settings/defaults.py:613 msgid "Northern Virginia" msgstr "" -#: settings/defaults.py:614 +#: awx/settings/defaults.py:614 msgid "London" msgstr "" -#: settings/defaults.py:615 +#: awx/settings/defaults.py:615 msgid "Sydney" msgstr "" -#: settings/defaults.py:616 +#: awx/settings/defaults.py:616 msgid "Hong Kong" msgstr "" -#: settings/defaults.py:643 +#: awx/settings/defaults.py:643 msgid "US East (Northern Virginia)" msgstr "" -#: settings/defaults.py:644 +#: awx/settings/defaults.py:644 msgid "US East (Ohio)" msgstr "" -#: settings/defaults.py:645 +#: awx/settings/defaults.py:645 msgid "US West (Oregon)" msgstr "" -#: settings/defaults.py:646 +#: awx/settings/defaults.py:646 msgid "US West (Northern California)" msgstr "" -#: settings/defaults.py:647 +#: awx/settings/defaults.py:647 msgid "Canada (Central)" msgstr "" -#: settings/defaults.py:648 +#: awx/settings/defaults.py:648 msgid "EU (Frankfurt)" msgstr "" -#: settings/defaults.py:649 +#: awx/settings/defaults.py:649 msgid "EU (Ireland)" msgstr "" -#: settings/defaults.py:650 +#: awx/settings/defaults.py:650 msgid "EU (London)" msgstr "" -#: settings/defaults.py:651 +#: awx/settings/defaults.py:651 msgid "Asia Pacific (Singapore)" msgstr "" -#: settings/defaults.py:652 +#: awx/settings/defaults.py:652 msgid "Asia Pacific (Sydney)" msgstr "" -#: settings/defaults.py:653 +#: awx/settings/defaults.py:653 msgid "Asia Pacific (Tokyo)" msgstr "" -#: settings/defaults.py:654 +#: awx/settings/defaults.py:654 msgid "Asia Pacific (Seoul)" msgstr "" -#: settings/defaults.py:655 +#: awx/settings/defaults.py:655 msgid "Asia Pacific (Mumbai)" msgstr "" -#: settings/defaults.py:656 +#: awx/settings/defaults.py:656 msgid "South America (Sao Paulo)" msgstr "" -#: settings/defaults.py:657 +#: awx/settings/defaults.py:657 msgid "US West (GovCloud)" msgstr "" -#: settings/defaults.py:658 +#: awx/settings/defaults.py:658 msgid "China (Beijing)" msgstr "" -#: settings/defaults.py:707 +#: awx/settings/defaults.py:707 msgid "US East (B)" msgstr "" -#: settings/defaults.py:708 +#: awx/settings/defaults.py:708 msgid "US East (C)" msgstr "" -#: settings/defaults.py:709 +#: awx/settings/defaults.py:709 msgid "US East (D)" msgstr "" -#: settings/defaults.py:710 +#: awx/settings/defaults.py:710 msgid "US Central (A)" msgstr "" -#: settings/defaults.py:711 +#: awx/settings/defaults.py:711 msgid "US Central (B)" msgstr "" -#: settings/defaults.py:712 +#: awx/settings/defaults.py:712 msgid "US Central (C)" msgstr "" -#: settings/defaults.py:713 +#: awx/settings/defaults.py:713 msgid "US Central (F)" msgstr "" -#: settings/defaults.py:714 +#: awx/settings/defaults.py:714 msgid "Europe West (B)" msgstr "" -#: settings/defaults.py:715 +#: awx/settings/defaults.py:715 msgid "Europe West (C)" msgstr "" -#: settings/defaults.py:716 +#: awx/settings/defaults.py:716 msgid "Europe West (D)" msgstr "" -#: settings/defaults.py:717 +#: awx/settings/defaults.py:717 msgid "Asia East (A)" msgstr "" -#: settings/defaults.py:718 +#: awx/settings/defaults.py:718 msgid "Asia East (B)" msgstr "" -#: settings/defaults.py:719 +#: awx/settings/defaults.py:719 msgid "Asia East (C)" msgstr "" -#: settings/defaults.py:743 +#: awx/settings/defaults.py:743 msgid "US Central" msgstr "" -#: settings/defaults.py:744 +#: awx/settings/defaults.py:744 msgid "US East" msgstr "" -#: settings/defaults.py:745 +#: awx/settings/defaults.py:745 msgid "US East 2" msgstr "" -#: settings/defaults.py:746 +#: awx/settings/defaults.py:746 msgid "US North Central" msgstr "" -#: settings/defaults.py:747 +#: awx/settings/defaults.py:747 msgid "US South Central" msgstr "" -#: settings/defaults.py:748 +#: awx/settings/defaults.py:748 msgid "US West" msgstr "" -#: settings/defaults.py:749 +#: awx/settings/defaults.py:749 msgid "Europe North" msgstr "" -#: settings/defaults.py:750 +#: awx/settings/defaults.py:750 msgid "Europe West" msgstr "" -#: settings/defaults.py:751 +#: awx/settings/defaults.py:751 msgid "Asia Pacific East" msgstr "" -#: settings/defaults.py:752 +#: awx/settings/defaults.py:752 msgid "Asia Pacific Southeast" msgstr "" -#: settings/defaults.py:753 +#: awx/settings/defaults.py:753 msgid "Japan East" msgstr "" -#: settings/defaults.py:754 +#: awx/settings/defaults.py:754 msgid "Japan West" msgstr "" -#: settings/defaults.py:755 +#: awx/settings/defaults.py:755 msgid "Brazil South" msgstr "" -#: sso/apps.py:9 +#: awx/sso/apps.py:9 msgid "Single Sign-On" msgstr "" -#: sso/conf.py:27 +#: awx/sso/conf.py:27 msgid "" "Mapping to organization admins/users from social auth accounts. This " "setting\n" @@ -2725,7 +2820,7 @@ msgid "" " remove_admins." msgstr "" -#: sso/conf.py:76 +#: awx/sso/conf.py:76 msgid "" "Mapping of team members (users) from social auth accounts. Keys are team\n" "names (will be created if not present). Values are dictionaries of options\n" @@ -2754,40 +2849,40 @@ msgid "" " the rules above will be removed from the team." msgstr "" -#: sso/conf.py:119 +#: awx/sso/conf.py:119 msgid "Authentication Backends" msgstr "" -#: sso/conf.py:120 +#: awx/sso/conf.py:120 msgid "" "List of authentication backends that are enabled based on license features " "and other authentication settings." msgstr "" -#: sso/conf.py:133 +#: awx/sso/conf.py:133 msgid "Social Auth Organization Map" msgstr "" -#: sso/conf.py:145 +#: awx/sso/conf.py:145 msgid "Social Auth Team Map" msgstr "" -#: sso/conf.py:157 +#: awx/sso/conf.py:157 msgid "Social Auth User Fields" msgstr "" -#: sso/conf.py:158 +#: awx/sso/conf.py:158 msgid "" "When set to an empty list `[]`, this setting prevents new user accounts from " "being created. Only users who have previously logged in using social auth or " "have a user account with a matching email address will be able to login." msgstr "" -#: sso/conf.py:176 +#: awx/sso/conf.py:176 msgid "LDAP Server URI" msgstr "" -#: sso/conf.py:177 +#: awx/sso/conf.py:177 msgid "" "URI to connect to LDAP server, such as \"ldap://ldap.example.com:389\" (non-" "SSL) or \"ldaps://ldap.example.com:636\" (SSL). Multiple LDAP servers may be " @@ -2795,18 +2890,19 @@ msgid "" "disabled if this parameter is empty." msgstr "" -#: sso/conf.py:181 sso/conf.py:199 sso/conf.py:211 sso/conf.py:223 -#: sso/conf.py:239 sso/conf.py:258 sso/conf.py:280 sso/conf.py:296 -#: sso/conf.py:315 sso/conf.py:332 sso/conf.py:349 sso/conf.py:365 -#: sso/conf.py:382 sso/conf.py:420 sso/conf.py:461 +#: awx/sso/conf.py:181 awx/sso/conf.py:199 awx/sso/conf.py:211 +#: awx/sso/conf.py:223 awx/sso/conf.py:239 awx/sso/conf.py:258 +#: awx/sso/conf.py:280 awx/sso/conf.py:296 awx/sso/conf.py:315 +#: awx/sso/conf.py:332 awx/sso/conf.py:349 awx/sso/conf.py:365 +#: awx/sso/conf.py:382 awx/sso/conf.py:420 awx/sso/conf.py:461 msgid "LDAP" msgstr "" -#: sso/conf.py:193 +#: awx/sso/conf.py:193 msgid "LDAP Bind DN" msgstr "" -#: sso/conf.py:194 +#: awx/sso/conf.py:194 msgid "" "DN (Distinguished Name) of user to bind for all search queries. Normally in " "the format \"CN=Some User,OU=Users,DC=example,DC=com\" but may also be " @@ -2814,27 +2910,27 @@ msgid "" "user account we will use to login to query LDAP for other user information." msgstr "" -#: sso/conf.py:209 +#: awx/sso/conf.py:209 msgid "LDAP Bind Password" msgstr "" -#: sso/conf.py:210 +#: awx/sso/conf.py:210 msgid "Password used to bind LDAP user account." msgstr "" -#: sso/conf.py:221 +#: awx/sso/conf.py:221 msgid "LDAP Start TLS" msgstr "" -#: sso/conf.py:222 +#: awx/sso/conf.py:222 msgid "Whether to enable TLS when the LDAP connection is not using SSL." msgstr "" -#: sso/conf.py:232 +#: awx/sso/conf.py:232 msgid "LDAP Connection Options" msgstr "" -#: sso/conf.py:233 +#: awx/sso/conf.py:233 msgid "" "Additional options to set for the LDAP connection. LDAP referrals are " "disabled by default (to prevent certain LDAP queries from hanging with AD). " @@ -2843,11 +2939,11 @@ msgid "" "values that can be set." msgstr "" -#: sso/conf.py:251 +#: awx/sso/conf.py:251 msgid "LDAP User Search" msgstr "" -#: sso/conf.py:252 +#: awx/sso/conf.py:252 msgid "" "LDAP search query to find users. Any user that matches the given pattern " "will be able to login to Tower. The user should also be mapped into an " @@ -2856,11 +2952,11 @@ msgid "" "possible. See python-ldap documentation as linked at the top of this section." msgstr "" -#: sso/conf.py:274 +#: awx/sso/conf.py:274 msgid "LDAP User DN Template" msgstr "" -#: sso/conf.py:275 +#: awx/sso/conf.py:275 msgid "" "Alternative to user search, if user DNs are all of the same format. This " "approach will be more efficient for user lookups than searching if it is " @@ -2868,11 +2964,11 @@ msgid "" "will be used instead of AUTH_LDAP_USER_SEARCH." msgstr "" -#: sso/conf.py:290 +#: awx/sso/conf.py:290 msgid "LDAP User Attribute Map" msgstr "" -#: sso/conf.py:291 +#: awx/sso/conf.py:291 msgid "" "Mapping of LDAP user schema to Tower API user attributes (key is user " "attribute name, value is LDAP attribute name). The default setting is valid " @@ -2880,54 +2976,54 @@ msgid "" "change the values (not the keys) of the dictionary/hash-table." msgstr "" -#: sso/conf.py:310 +#: awx/sso/conf.py:310 msgid "LDAP Group Search" msgstr "" -#: sso/conf.py:311 +#: awx/sso/conf.py:311 msgid "" "Users in Tower are mapped to organizations based on their membership in LDAP " "groups. This setting defines the LDAP search query to find groups. Note that " "this, unlike the user search above, does not support LDAPSearchUnion." msgstr "" -#: sso/conf.py:328 +#: awx/sso/conf.py:328 msgid "LDAP Group Type" msgstr "" -#: sso/conf.py:329 +#: awx/sso/conf.py:329 msgid "" "The group type may need to be changed based on the type of the LDAP server. " "Values are listed at: http://pythonhosted.org/django-auth-ldap/groups." "html#types-of-groups" msgstr "" -#: sso/conf.py:344 +#: awx/sso/conf.py:344 msgid "LDAP Require Group" msgstr "" -#: sso/conf.py:345 +#: awx/sso/conf.py:345 msgid "" "Group DN required to login. If specified, user must be a member of this " "group to login via LDAP. If not set, everyone in LDAP that matches the user " "search will be able to login via Tower. Only one require group is supported." msgstr "" -#: sso/conf.py:361 +#: awx/sso/conf.py:361 msgid "LDAP Deny Group" msgstr "" -#: sso/conf.py:362 +#: awx/sso/conf.py:362 msgid "" "Group DN denied from login. If specified, user will not be allowed to login " "if a member of this group. Only one deny group is supported." msgstr "" -#: sso/conf.py:375 +#: awx/sso/conf.py:375 msgid "LDAP User Flags By Group" msgstr "" -#: sso/conf.py:376 +#: awx/sso/conf.py:376 msgid "" "User profile flags updated from group membership (key is user attribute " "name, value is group DN). These are boolean fields that are matched based " @@ -2936,11 +3032,11 @@ msgid "" "false at login time based on current LDAP settings." msgstr "" -#: sso/conf.py:394 +#: awx/sso/conf.py:394 msgid "LDAP Organization Map" msgstr "" -#: sso/conf.py:395 +#: awx/sso/conf.py:395 msgid "" "Mapping between organization admins/users and LDAP groups. This controls " "what users are placed into what Tower organizations relative to their LDAP " @@ -2967,11 +3063,11 @@ msgid "" "remove_admins." msgstr "" -#: sso/conf.py:443 +#: awx/sso/conf.py:443 msgid "LDAP Team Map" msgstr "" -#: sso/conf.py:444 +#: awx/sso/conf.py:444 msgid "" "Mapping between team members (users) and LDAP groups. Keys are team names " "(will be created if not present). Values are dictionaries of options for " @@ -2990,87 +3086,88 @@ msgid "" "of the given groups will be removed from the team." msgstr "" -#: sso/conf.py:487 +#: awx/sso/conf.py:487 msgid "RADIUS Server" msgstr "" -#: sso/conf.py:488 +#: awx/sso/conf.py:488 msgid "" "Hostname/IP of RADIUS server. RADIUS authentication will be disabled if this " "setting is empty." msgstr "" -#: sso/conf.py:490 sso/conf.py:504 sso/conf.py:516 +#: awx/sso/conf.py:490 awx/sso/conf.py:504 awx/sso/conf.py:516 msgid "RADIUS" msgstr "" -#: sso/conf.py:502 +#: awx/sso/conf.py:502 msgid "RADIUS Port" msgstr "" -#: sso/conf.py:503 +#: awx/sso/conf.py:503 msgid "Port of RADIUS server." msgstr "" -#: sso/conf.py:514 +#: awx/sso/conf.py:514 msgid "RADIUS Secret" msgstr "" -#: sso/conf.py:515 +#: awx/sso/conf.py:515 msgid "Shared secret for authenticating to RADIUS server." msgstr "" -#: sso/conf.py:531 +#: awx/sso/conf.py:531 msgid "Google OAuth2 Callback URL" msgstr "" -#: sso/conf.py:532 +#: awx/sso/conf.py:532 msgid "" "Create a project at https://console.developers.google.com/ to obtain an " "OAuth2 key and secret for a web application. Ensure that the Google+ API is " "enabled. Provide this URL as the callback URL for your application." msgstr "" -#: sso/conf.py:536 sso/conf.py:547 sso/conf.py:558 sso/conf.py:571 -#: sso/conf.py:585 sso/conf.py:597 sso/conf.py:609 +#: awx/sso/conf.py:536 awx/sso/conf.py:547 awx/sso/conf.py:558 +#: awx/sso/conf.py:571 awx/sso/conf.py:585 awx/sso/conf.py:597 +#: awx/sso/conf.py:609 msgid "Google OAuth2" msgstr "" -#: sso/conf.py:545 +#: awx/sso/conf.py:545 msgid "Google OAuth2 Key" msgstr "" -#: sso/conf.py:546 +#: awx/sso/conf.py:546 msgid "" "The OAuth2 key from your web application at https://console.developers." "google.com/." msgstr "" -#: sso/conf.py:556 +#: awx/sso/conf.py:556 msgid "Google OAuth2 Secret" msgstr "" -#: sso/conf.py:557 +#: awx/sso/conf.py:557 msgid "" "The OAuth2 secret from your web application at https://console.developers." "google.com/." msgstr "" -#: sso/conf.py:568 +#: awx/sso/conf.py:568 msgid "Google OAuth2 Whitelisted Domains" msgstr "" -#: sso/conf.py:569 +#: awx/sso/conf.py:569 msgid "" "Update this setting to restrict the domains who are allowed to login using " "Google OAuth2." msgstr "" -#: sso/conf.py:580 +#: awx/sso/conf.py:580 msgid "Google OAuth2 Extra Arguments" msgstr "" -#: sso/conf.py:581 +#: awx/sso/conf.py:581 msgid "" "Extra arguments for Google OAuth2 login. When only allowing a single domain " "to authenticate, set to `{\"hd\": \"yourdomain.com\"}` and Google will not " @@ -3078,60 +3175,60 @@ msgid "" "Google accounts." msgstr "" -#: sso/conf.py:595 +#: awx/sso/conf.py:595 msgid "Google OAuth2 Organization Map" msgstr "" -#: sso/conf.py:607 +#: awx/sso/conf.py:607 msgid "Google OAuth2 Team Map" msgstr "" -#: sso/conf.py:623 +#: awx/sso/conf.py:623 msgid "GitHub OAuth2 Callback URL" msgstr "" -#: sso/conf.py:624 +#: awx/sso/conf.py:624 msgid "" "Create a developer application at https://github.com/settings/developers to " "obtain an OAuth2 key (Client ID) and secret (Client Secret). Provide this " "URL as the callback URL for your application." msgstr "" -#: sso/conf.py:628 sso/conf.py:639 sso/conf.py:649 sso/conf.py:661 -#: sso/conf.py:673 +#: awx/sso/conf.py:628 awx/sso/conf.py:639 awx/sso/conf.py:649 +#: awx/sso/conf.py:661 awx/sso/conf.py:673 msgid "GitHub OAuth2" msgstr "" -#: sso/conf.py:637 +#: awx/sso/conf.py:637 msgid "GitHub OAuth2 Key" msgstr "" -#: sso/conf.py:638 +#: awx/sso/conf.py:638 msgid "The OAuth2 key (Client ID) from your GitHub developer application." msgstr "" -#: sso/conf.py:647 +#: awx/sso/conf.py:647 msgid "GitHub OAuth2 Secret" msgstr "" -#: sso/conf.py:648 +#: awx/sso/conf.py:648 msgid "" "The OAuth2 secret (Client Secret) from your GitHub developer application." msgstr "" -#: sso/conf.py:659 +#: awx/sso/conf.py:659 msgid "GitHub OAuth2 Organization Map" msgstr "" -#: sso/conf.py:671 +#: awx/sso/conf.py:671 msgid "GitHub OAuth2 Team Map" msgstr "" -#: sso/conf.py:687 +#: awx/sso/conf.py:687 msgid "GitHub Organization OAuth2 Callback URL" msgstr "" -#: sso/conf.py:688 sso/conf.py:763 +#: awx/sso/conf.py:688 awx/sso/conf.py:763 msgid "" "Create an organization-owned application at https://github.com/organizations/" "/settings/applications and obtain an OAuth2 key (Client ID) and " @@ -3139,86 +3236,86 @@ msgid "" "application." msgstr "" -#: sso/conf.py:692 sso/conf.py:703 sso/conf.py:713 sso/conf.py:725 -#: sso/conf.py:736 sso/conf.py:748 +#: awx/sso/conf.py:692 awx/sso/conf.py:703 awx/sso/conf.py:713 +#: awx/sso/conf.py:725 awx/sso/conf.py:736 awx/sso/conf.py:748 msgid "GitHub Organization OAuth2" msgstr "" -#: sso/conf.py:701 +#: awx/sso/conf.py:701 msgid "GitHub Organization OAuth2 Key" msgstr "" -#: sso/conf.py:702 sso/conf.py:777 +#: awx/sso/conf.py:702 awx/sso/conf.py:777 msgid "The OAuth2 key (Client ID) from your GitHub organization application." msgstr "" -#: sso/conf.py:711 +#: awx/sso/conf.py:711 msgid "GitHub Organization OAuth2 Secret" msgstr "" -#: sso/conf.py:712 sso/conf.py:787 +#: awx/sso/conf.py:712 awx/sso/conf.py:787 msgid "" "The OAuth2 secret (Client Secret) from your GitHub organization application." msgstr "" -#: sso/conf.py:722 +#: awx/sso/conf.py:722 msgid "GitHub Organization Name" msgstr "" -#: sso/conf.py:723 +#: awx/sso/conf.py:723 msgid "" "The name of your GitHub organization, as used in your organization's URL: " "https://github.com//." msgstr "" -#: sso/conf.py:734 +#: awx/sso/conf.py:734 msgid "GitHub Organization OAuth2 Organization Map" msgstr "" -#: sso/conf.py:746 +#: awx/sso/conf.py:746 msgid "GitHub Organization OAuth2 Team Map" msgstr "" -#: sso/conf.py:762 +#: awx/sso/conf.py:762 msgid "GitHub Team OAuth2 Callback URL" msgstr "" -#: sso/conf.py:767 sso/conf.py:778 sso/conf.py:788 sso/conf.py:800 -#: sso/conf.py:811 sso/conf.py:823 +#: awx/sso/conf.py:767 awx/sso/conf.py:778 awx/sso/conf.py:788 +#: awx/sso/conf.py:800 awx/sso/conf.py:811 awx/sso/conf.py:823 msgid "GitHub Team OAuth2" msgstr "" -#: sso/conf.py:776 +#: awx/sso/conf.py:776 msgid "GitHub Team OAuth2 Key" msgstr "" -#: sso/conf.py:786 +#: awx/sso/conf.py:786 msgid "GitHub Team OAuth2 Secret" msgstr "" -#: sso/conf.py:797 +#: awx/sso/conf.py:797 msgid "GitHub Team ID" msgstr "" -#: sso/conf.py:798 +#: awx/sso/conf.py:798 msgid "" "Find the numeric team ID using the Github API: http://fabian-kostadinov." "github.io/2015/01/16/how-to-find-a-github-team-id/." msgstr "" -#: sso/conf.py:809 +#: awx/sso/conf.py:809 msgid "GitHub Team OAuth2 Organization Map" msgstr "" -#: sso/conf.py:821 +#: awx/sso/conf.py:821 msgid "GitHub Team OAuth2 Team Map" msgstr "" -#: sso/conf.py:837 +#: awx/sso/conf.py:837 msgid "Azure AD OAuth2 Callback URL" msgstr "" -#: sso/conf.py:838 +#: awx/sso/conf.py:838 msgid "" "Register an Azure AD application as described by https://msdn.microsoft.com/" "en-us/library/azure/dn132599.aspx and obtain an OAuth2 key (Client ID) and " @@ -3226,117 +3323,118 @@ msgid "" "application." msgstr "" -#: sso/conf.py:842 sso/conf.py:853 sso/conf.py:863 sso/conf.py:875 -#: sso/conf.py:887 +#: awx/sso/conf.py:842 awx/sso/conf.py:853 awx/sso/conf.py:863 +#: awx/sso/conf.py:875 awx/sso/conf.py:887 msgid "Azure AD OAuth2" msgstr "" -#: sso/conf.py:851 +#: awx/sso/conf.py:851 msgid "Azure AD OAuth2 Key" msgstr "" -#: sso/conf.py:852 +#: awx/sso/conf.py:852 msgid "The OAuth2 key (Client ID) from your Azure AD application." msgstr "" -#: sso/conf.py:861 +#: awx/sso/conf.py:861 msgid "Azure AD OAuth2 Secret" msgstr "" -#: sso/conf.py:862 +#: awx/sso/conf.py:862 msgid "The OAuth2 secret (Client Secret) from your Azure AD application." msgstr "" -#: sso/conf.py:873 +#: awx/sso/conf.py:873 msgid "Azure AD OAuth2 Organization Map" msgstr "" -#: sso/conf.py:885 +#: awx/sso/conf.py:885 msgid "Azure AD OAuth2 Team Map" msgstr "" -#: sso/conf.py:906 +#: awx/sso/conf.py:906 msgid "SAML Service Provider Callback URL" msgstr "" -#: sso/conf.py:907 +#: awx/sso/conf.py:907 msgid "" "Register Tower as a service provider (SP) with each identity provider (IdP) " "you have configured. Provide your SP Entity ID and this callback URL for " "your application." msgstr "" -#: sso/conf.py:910 sso/conf.py:924 sso/conf.py:937 sso/conf.py:951 -#: sso/conf.py:965 sso/conf.py:983 sso/conf.py:1005 sso/conf.py:1024 -#: sso/conf.py:1044 sso/conf.py:1078 sso/conf.py:1091 +#: awx/sso/conf.py:910 awx/sso/conf.py:924 awx/sso/conf.py:937 +#: awx/sso/conf.py:951 awx/sso/conf.py:965 awx/sso/conf.py:983 +#: awx/sso/conf.py:1005 awx/sso/conf.py:1024 awx/sso/conf.py:1044 +#: awx/sso/conf.py:1078 awx/sso/conf.py:1091 msgid "SAML" msgstr "" -#: sso/conf.py:921 +#: awx/sso/conf.py:921 msgid "SAML Service Provider Metadata URL" msgstr "" -#: sso/conf.py:922 +#: awx/sso/conf.py:922 msgid "" "If your identity provider (IdP) allows uploading an XML metadata file, you " "can download one from this URL." msgstr "" -#: sso/conf.py:934 +#: awx/sso/conf.py:934 msgid "SAML Service Provider Entity ID" msgstr "" -#: sso/conf.py:935 +#: awx/sso/conf.py:935 msgid "" "The application-defined unique identifier used as the audience of the SAML " "service provider (SP) configuration." msgstr "" -#: sso/conf.py:948 +#: awx/sso/conf.py:948 msgid "SAML Service Provider Public Certificate" msgstr "" -#: sso/conf.py:949 +#: awx/sso/conf.py:949 msgid "" "Create a keypair for Tower to use as a service provider (SP) and include the " "certificate content here." msgstr "" -#: sso/conf.py:962 +#: awx/sso/conf.py:962 msgid "SAML Service Provider Private Key" msgstr "" -#: sso/conf.py:963 +#: awx/sso/conf.py:963 msgid "" "Create a keypair for Tower to use as a service provider (SP) and include the " "private key content here." msgstr "" -#: sso/conf.py:981 +#: awx/sso/conf.py:981 msgid "SAML Service Provider Organization Info" msgstr "" -#: sso/conf.py:982 +#: awx/sso/conf.py:982 msgid "Configure this setting with information about your app." msgstr "" -#: sso/conf.py:1003 +#: awx/sso/conf.py:1003 msgid "SAML Service Provider Technical Contact" msgstr "" -#: sso/conf.py:1004 sso/conf.py:1023 +#: awx/sso/conf.py:1004 awx/sso/conf.py:1023 msgid "Configure this setting with your contact information." msgstr "" -#: sso/conf.py:1022 +#: awx/sso/conf.py:1022 msgid "SAML Service Provider Support Contact" msgstr "" -#: sso/conf.py:1037 +#: awx/sso/conf.py:1037 msgid "SAML Enabled Identity Providers" msgstr "" -#: sso/conf.py:1038 +#: awx/sso/conf.py:1038 msgid "" "Configure the Entity ID, SSO URL and certificate for each identity provider " "(IdP) in use. Multiple SAML IdPs are supported. Some IdPs may provide user " @@ -3345,217 +3443,237 @@ msgid "" "Attribute names may be overridden for each IdP." msgstr "" -#: sso/conf.py:1076 +#: awx/sso/conf.py:1076 msgid "SAML Organization Map" msgstr "" -#: sso/conf.py:1089 +#: awx/sso/conf.py:1089 msgid "SAML Team Map" msgstr "" -#: sso/fields.py:123 +#: awx/sso/fields.py:123 +#, python-brace-format msgid "Invalid connection option(s): {invalid_options}." msgstr "" -#: sso/fields.py:194 +#: awx/sso/fields.py:194 msgid "Base" msgstr "" -#: sso/fields.py:195 +#: awx/sso/fields.py:195 msgid "One Level" msgstr "" -#: sso/fields.py:196 +#: awx/sso/fields.py:196 msgid "Subtree" msgstr "" -#: sso/fields.py:214 +#: awx/sso/fields.py:214 +#, python-brace-format msgid "Expected a list of three items but got {length} instead." msgstr "" -#: sso/fields.py:215 +#: awx/sso/fields.py:215 +#, python-brace-format msgid "Expected an instance of LDAPSearch but got {input_type} instead." msgstr "" -#: sso/fields.py:251 +#: awx/sso/fields.py:251 +#, python-brace-format msgid "" "Expected an instance of LDAPSearch or LDAPSearchUnion but got {input_type} " "instead." msgstr "" -#: sso/fields.py:278 +#: awx/sso/fields.py:278 +#, python-brace-format msgid "Invalid user attribute(s): {invalid_attrs}." msgstr "" -#: sso/fields.py:295 +#: awx/sso/fields.py:295 +#, python-brace-format msgid "Expected an instance of LDAPGroupType but got {input_type} instead." msgstr "" -#: sso/fields.py:323 +#: awx/sso/fields.py:323 +#, python-brace-format msgid "Invalid user flag: \"{invalid_flag}\"." msgstr "" -#: sso/fields.py:339 sso/fields.py:506 +#: awx/sso/fields.py:339 awx/sso/fields.py:506 +#, python-brace-format msgid "" "Expected None, True, False, a string or list of strings but got {input_type} " "instead." msgstr "" -#: sso/fields.py:375 +#: awx/sso/fields.py:375 +#, python-brace-format msgid "Missing key(s): {missing_keys}." msgstr "" -#: sso/fields.py:376 +#: awx/sso/fields.py:376 +#, python-brace-format msgid "Invalid key(s): {invalid_keys}." msgstr "" -#: sso/fields.py:425 sso/fields.py:542 +#: awx/sso/fields.py:425 awx/sso/fields.py:542 +#, python-brace-format msgid "Invalid key(s) for organization map: {invalid_keys}." msgstr "" -#: sso/fields.py:443 +#: awx/sso/fields.py:443 +#, python-brace-format msgid "Missing required key for team map: {invalid_keys}." msgstr "" -#: sso/fields.py:444 sso/fields.py:561 +#: awx/sso/fields.py:444 awx/sso/fields.py:561 +#, python-brace-format msgid "Invalid key(s) for team map: {invalid_keys}." msgstr "" -#: sso/fields.py:560 +#: awx/sso/fields.py:560 +#, python-brace-format msgid "Missing required key for team map: {missing_keys}." msgstr "" -#: sso/fields.py:578 +#: awx/sso/fields.py:578 +#, python-brace-format msgid "Missing required key(s) for org info record: {missing_keys}." msgstr "" -#: sso/fields.py:591 +#: awx/sso/fields.py:591 +#, python-brace-format msgid "Invalid language code(s) for org info: {invalid_lang_codes}." msgstr "" -#: sso/fields.py:610 +#: awx/sso/fields.py:610 +#, python-brace-format msgid "Missing required key(s) for contact: {missing_keys}." msgstr "" -#: sso/fields.py:622 +#: awx/sso/fields.py:622 +#, python-brace-format msgid "Missing required key(s) for IdP: {missing_keys}." msgstr "" -#: sso/pipeline.py:24 +#: awx/sso/pipeline.py:24 +#, python-brace-format msgid "An account cannot be found for {0}" msgstr "" -#: sso/pipeline.py:30 +#: awx/sso/pipeline.py:30 msgid "Your account is inactive" msgstr "" -#: sso/validators.py:19 sso/validators.py:44 +#: awx/sso/validators.py:19 awx/sso/validators.py:44 #, python-format msgid "DN must include \"%%(user)s\" placeholder for username: %s" msgstr "" -#: sso/validators.py:26 +#: awx/sso/validators.py:26 #, python-format msgid "Invalid DN: %s" msgstr "" -#: sso/validators.py:56 +#: awx/sso/validators.py:56 #, python-format msgid "Invalid filter: %s" msgstr "" -#: templates/error.html:4 ui/templates/ui/index.html:8 +#: awx/templates/error.html:4 awx/ui/templates/ui/index.html:8 msgid "Ansible Tower" msgstr "" -#: templates/rest_framework/api.html:39 +#: awx/templates/rest_framework/api.html:39 msgid "Ansible Tower API Guide" msgstr "" -#: templates/rest_framework/api.html:40 +#: awx/templates/rest_framework/api.html:40 msgid "Back to Ansible Tower" msgstr "" -#: templates/rest_framework/api.html:41 +#: awx/templates/rest_framework/api.html:41 msgid "Resize" msgstr "" -#: templates/rest_framework/base.html:78 templates/rest_framework/base.html:92 +#: awx/templates/rest_framework/base.html:78 +#: awx/templates/rest_framework/base.html:92 #, python-format msgid "Make a GET request on the %(name)s resource" msgstr "" -#: templates/rest_framework/base.html:80 +#: awx/templates/rest_framework/base.html:80 msgid "Specify a format for the GET request" msgstr "" -#: templates/rest_framework/base.html:86 +#: awx/templates/rest_framework/base.html:86 #, python-format msgid "" "Make a GET request on the %(name)s resource with the format set to `" "%(format)s`" msgstr "" -#: templates/rest_framework/base.html:100 +#: awx/templates/rest_framework/base.html:100 #, python-format msgid "Make an OPTIONS request on the %(name)s resource" msgstr "" -#: templates/rest_framework/base.html:106 +#: awx/templates/rest_framework/base.html:106 #, python-format msgid "Make a DELETE request on the %(name)s resource" msgstr "" -#: templates/rest_framework/base.html:113 +#: awx/templates/rest_framework/base.html:113 msgid "Filters" msgstr "" -#: templates/rest_framework/base.html:172 -#: templates/rest_framework/base.html:186 +#: awx/templates/rest_framework/base.html:172 +#: awx/templates/rest_framework/base.html:186 #, python-format msgid "Make a POST request on the %(name)s resource" msgstr "" -#: templates/rest_framework/base.html:216 -#: templates/rest_framework/base.html:230 +#: awx/templates/rest_framework/base.html:216 +#: awx/templates/rest_framework/base.html:230 #, python-format msgid "Make a PUT request on the %(name)s resource" msgstr "" -#: templates/rest_framework/base.html:233 +#: awx/templates/rest_framework/base.html:233 #, python-format msgid "Make a PATCH request on the %(name)s resource" msgstr "" -#: ui/apps.py:9 ui/conf.py:22 ui/conf.py:38 ui/conf.py:53 +#: awx/ui/apps.py:9 awx/ui/conf.py:22 awx/ui/conf.py:38 awx/ui/conf.py:53 msgid "UI" msgstr "" -#: ui/conf.py:16 +#: awx/ui/conf.py:16 msgid "Off" msgstr "" -#: ui/conf.py:17 +#: awx/ui/conf.py:17 msgid "Anonymous" msgstr "" -#: ui/conf.py:18 +#: awx/ui/conf.py:18 msgid "Detailed" msgstr "" -#: ui/conf.py:20 +#: awx/ui/conf.py:20 msgid "Analytics Tracking State" msgstr "" -#: ui/conf.py:21 +#: awx/ui/conf.py:21 msgid "Enable or Disable Analytics Tracking." msgstr "" -#: ui/conf.py:31 +#: awx/ui/conf.py:31 msgid "Custom Login Info" msgstr "" -#: ui/conf.py:32 +#: awx/ui/conf.py:32 msgid "" "If needed, you can add specific information (such as a legal notice or a " "disclaimer) to a text box in the login modal using this setting. Any content " @@ -3564,42 +3682,42 @@ msgid "" "(paragraphs) must be escaped as `\\n` within the block of text." msgstr "" -#: ui/conf.py:48 +#: awx/ui/conf.py:48 msgid "Custom Logo" msgstr "" -#: ui/conf.py:49 +#: awx/ui/conf.py:49 msgid "" "To set up a custom logo, provide a file that you create. For the custom logo " "to look its best, use a `.png` file with a transparent background. GIF, PNG " "and JPEG formats are supported." msgstr "" -#: ui/fields.py:29 +#: awx/ui/fields.py:29 msgid "" "Invalid format for custom logo. Must be a data URL with a base64-encoded " "GIF, PNG or JPEG image." msgstr "" -#: ui/fields.py:30 +#: awx/ui/fields.py:30 msgid "Invalid base64-encoded data in data URL." msgstr "" -#: ui/templates/ui/index.html:49 +#: awx/ui/templates/ui/index.html:49 msgid "" "Your session will expire in 60 seconds, would you like to continue?" msgstr "" -#: ui/templates/ui/index.html:64 +#: awx/ui/templates/ui/index.html:64 msgid "CANCEL" msgstr "" -#: ui/templates/ui/index.html:116 +#: awx/ui/templates/ui/index.html:116 msgid "Set how many days of data should be retained." msgstr "" -#: ui/templates/ui/index.html:122 +#: awx/ui/templates/ui/index.html:122 msgid "" "Please enter an integer that is not " @@ -3608,7 +3726,7 @@ msgid "" "span>." msgstr "" -#: ui/templates/ui/index.html:127 +#: awx/ui/templates/ui/index.html:127 msgid "" "For facts collected older than the time period specified, save one fact scan " "(snapshot) per time window (frequency). For example, facts older than 30 " @@ -3620,11 +3738,11 @@ msgid "" "
" msgstr "" -#: ui/templates/ui/index.html:136 +#: awx/ui/templates/ui/index.html:136 msgid "Select a time period after which to remove old facts" msgstr "" -#: ui/templates/ui/index.html:150 +#: awx/ui/templates/ui/index.html:150 msgid "" "Please enter an integer " @@ -3633,11 +3751,11 @@ msgid "" "that is lower than 9999." msgstr "" -#: ui/templates/ui/index.html:155 +#: awx/ui/templates/ui/index.html:155 msgid "Select a frequency for snapshot retention" msgstr "" -#: ui/templates/ui/index.html:169 +#: awx/ui/templates/ui/index.html:169 msgid "" "Please enter an integer." msgstr "" -#: ui/templates/ui/index.html:175 +#: awx/ui/templates/ui/index.html:175 msgid "working..." msgstr "" diff --git a/awx/main/access.py b/awx/main/access.py index 059e89e655..7bef51a20f 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -2109,7 +2109,7 @@ class ActivityStreamAccess(BaseAccess): 'job_template', 'job', 'ad_hoc_command', 'notification_template', 'notification', 'label', 'role', 'actor', 'schedule', 'custom_inventory_script', 'unified_job_template', - 'workflow_job_template', 'workflow_job') + 'workflow_job_template', 'workflow_job', 'workflow_job_template_node') if self.user.is_superuser or self.user.is_system_auditor: return qs.all() diff --git a/awx/main/models/__init__.py b/awx/main/models/__init__.py index 3f7e309940..d7b65d8107 100644 --- a/awx/main/models/__init__.py +++ b/awx/main/models/__init__.py @@ -126,4 +126,5 @@ activity_stream_registrar.connect(Notification) activity_stream_registrar.connect(Label) activity_stream_registrar.connect(User) activity_stream_registrar.connect(WorkflowJobTemplate) +activity_stream_registrar.connect(WorkflowJobTemplateNode) activity_stream_registrar.connect(WorkflowJob) diff --git a/awx/main/models/mixins.py b/awx/main/models/mixins.py index 80eabf3495..952377c112 100644 --- a/awx/main/models/mixins.py +++ b/awx/main/models/mixins.py @@ -127,10 +127,10 @@ class SurveyJobTemplateMixin(models.Model): # Overwrite with job template extra vars with survey default vars if self.survey_enabled and 'spec' in self.survey_spec: for survey_element in self.survey_spec.get("spec", []): - default = survey_element['default'] - variable_key = survey_element['variable'] + default = survey_element.get('default') + variable_key = survey_element.get('variable') if survey_element.get('type') == 'password': - if variable_key in kwargs_extra_vars: + if variable_key in kwargs_extra_vars and default: kw_value = kwargs_extra_vars[variable_key] if kw_value.startswith('$encrypted$') and kw_value != default: kwargs_extra_vars[variable_key] = default diff --git a/awx/main/models/rbac.py b/awx/main/models/rbac.py index 9e40846b42..2a8238da74 100644 --- a/awx/main/models/rbac.py +++ b/awx/main/models/rbac.py @@ -10,9 +10,9 @@ import re # Django from django.db import models, transaction, connection from django.core.urlresolvers import reverse -from django.utils.translation import ugettext_lazy as _ from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey +from django.utils.translation import ugettext_lazy as _ # AWX @@ -33,29 +33,29 @@ ROLE_SINGLETON_SYSTEM_ADMINISTRATOR='system_administrator' ROLE_SINGLETON_SYSTEM_AUDITOR='system_auditor' role_names = { - 'system_administrator' : 'System Administrator', - 'system_auditor' : 'System Auditor', - 'adhoc_role' : 'Ad Hoc', - 'admin_role' : 'Admin', - 'auditor_role' : 'Auditor', - 'execute_role' : 'Execute', - 'member_role' : 'Member', - 'read_role' : 'Read', - 'update_role' : 'Update', - 'use_role' : 'Use', + 'system_administrator' : _('System Administrator'), + 'system_auditor' : _('System Auditor'), + 'adhoc_role' : _('Ad Hoc'), + 'admin_role' : _('Admin'), + 'auditor_role' : _('Auditor'), + 'execute_role' : _('Execute'), + 'member_role' : _('Member'), + 'read_role' : _('Read'), + 'update_role' : _('Update'), + 'use_role' : _('Use'), } role_descriptions = { - 'system_administrator' : 'Can manage all aspects of the system', - 'system_auditor' : 'Can view all settings on the system', - 'adhoc_role' : 'May run ad hoc commands on an inventory', - 'admin_role' : 'Can manage all aspects of the %s', - 'auditor_role' : 'Can view all settings for the %s', - 'execute_role' : 'May run the %s', - 'member_role' : 'User is a member of the %s', - 'read_role' : 'May view settings for the %s', - 'update_role' : 'May update project or inventory or group using the configured source update system', - 'use_role' : 'Can use the %s in a job template', + 'system_administrator' : _('Can manage all aspects of the system'), + 'system_auditor' : _('Can view all settings on the system'), + 'adhoc_role' : _('May run ad hoc commands on an inventory'), + 'admin_role' : _('Can manage all aspects of the %s'), + 'auditor_role' : _('Can view all settings for the %s'), + 'execute_role' : _('May run the %s'), + 'member_role' : _('User is a member of the %s'), + 'read_role' : _('May view settings for the %s'), + 'update_role' : _('May update project or inventory or group using the configured source update system'), + 'use_role' : _('Can use the %s in a job template'), } diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 4da3da0f59..4f0484f76d 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -721,7 +721,7 @@ class BaseTask(Task): stdout_handle = self.get_stdout_handle(instance) if self.should_use_proot(instance, **kwargs): if not check_proot_installed(): - raise RuntimeError('proot is not installed') + raise RuntimeError('bubblewrap is not installed') kwargs['proot_temp_dir'] = build_proot_temp_dir() args = wrap_args_with_proot(args, cwd, **kwargs) safe_args = wrap_args_with_proot(safe_args, cwd, **kwargs) @@ -874,7 +874,7 @@ class RunJob(BaseTask): cp_dir = os.path.join(kwargs['private_data_dir'], 'cp') if not os.path.exists(cp_dir): os.mkdir(cp_dir, 0700) - env['ANSIBLE_SSH_CONTROL_PATH'] = os.path.join(cp_dir, 'ansible-ssh-%%h-%%p-%%r') + env['ANSIBLE_SSH_CONTROL_PATH'] = os.path.join(cp_dir, '%%h%%p%%r') # Allow the inventory script to include host variables inline via ['_meta']['hostvars']. env['INVENTORY_HOSTVARS'] = str(True) @@ -1609,7 +1609,6 @@ class RunInventoryUpdate(BaseTask): if inventory_update.overwrite_vars: args.append('--overwrite-vars') args.append('--source') - # If this is a cloud-based inventory (e.g. from AWS, Rackspace, etc.) # then we need to set some extra flags based on settings in # Tower. @@ -1665,10 +1664,7 @@ class RunInventoryUpdate(BaseTask): os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) args.append(runpath) args.append("--custom") - # try: - # shutil.rmtree(runpath, True) - # except OSError: - # pass + self.custom_dir_path.append(runpath) verbosity = getattr(settings, 'INVENTORY_UPDATE_VERBOSITY', 1) args.append('-v%d' % verbosity) if settings.DEBUG: @@ -1690,6 +1686,19 @@ class RunInventoryUpdate(BaseTask): def get_idle_timeout(self): return getattr(settings, 'INVENTORY_UPDATE_IDLE_TIMEOUT', None) + def pre_run_hook(self, instance, **kwargs): + self.custom_dir_path = [] + + def post_run_hook(self, instance, status, **kwargs): + print("In post run hook") + if self.custom_dir_path: + for p in self.custom_dir_path: + try: + shutil.rmtree(p, True) + except OSError: + pass + + class RunAdHocCommand(BaseTask): ''' diff --git a/awx/main/tests/unit/api/test_views.py b/awx/main/tests/unit/api/test_views.py index 37b9177db7..3bea19cedd 100644 --- a/awx/main/tests/unit/api/test_views.py +++ b/awx/main/tests/unit/api/test_views.py @@ -1,9 +1,12 @@ import mock import pytest +from collections import namedtuple + from awx.api.views import ( ApiV1RootView, JobTemplateLabelList, + JobTemplateSurveySpec, ) @@ -65,3 +68,16 @@ class TestJobTemplateLabelList: super(JobTemplateLabelList, view).unattach(mock_request, None, None) assert mixin_unattach.called_with(mock_request, None, None) + + +class TestJobTemplateSurveySpec(object): + @mock.patch('awx.api.views.feature_enabled', lambda feature: True) + def test_get_password_type(self, mocker, mock_response_new): + JobTemplate = namedtuple('JobTemplate', 'survey_spec') + obj = JobTemplate(survey_spec={'spec':[{'type': 'password', 'default': 'my_default'}]}) + with mocker.patch.object(JobTemplateSurveySpec, 'get_object', return_value=obj): + view = JobTemplateSurveySpec() + response = view.get(mocker.MagicMock()) + assert response == mock_response_new + # which there was a better way to do this! + assert response.call_args[0][1]['spec'][0]['default'] == '$encrypted$' diff --git a/awx/main/tests/unit/models/test_job_template_unit.py b/awx/main/tests/unit/models/test_job_template_unit.py index 28f2dc2993..dade874617 100644 --- a/awx/main/tests/unit/models/test_job_template_unit.py +++ b/awx/main/tests/unit/models/test_job_template_unit.py @@ -84,3 +84,18 @@ def test_job_template_survey_variable_validation(job_template_factory): } obj.survey_enabled = True assert obj.survey_variable_validation({"a": 5}) == ["Value 5 for 'a' expected to be a string."] + + +def test_job_template_survey_mixin(job_template_factory): + objects = job_template_factory( + 'survey_mixin_test', + organization='org1', + inventory='inventory1', + credential='cred1', + persisted=False, + ) + obj = objects.job_template + obj.survey_enabled = True + obj.survey_spec = {'spec': [{'default':'my_default', 'type':'password', 'variable':'my_variable'}]} + kwargs = obj._update_unified_job_kwargs(extra_vars={'my_variable':'$encrypted$'}) + assert kwargs['extra_vars'] == '{"my_variable": "my_default"}' diff --git a/awx/ui/client/src/about/about.route.js b/awx/ui/client/src/about/about.route.js index 475cf1aea0..639c5ee975 100644 --- a/awx/ui/client/src/about/about.route.js +++ b/awx/ui/client/src/about/about.route.js @@ -1,12 +1,13 @@ import {templateUrl} from '../shared/template-url/template-url.factory'; import controller from './about.controller'; +import { N_ } from '../i18n'; export default { name: 'setup.about', route: '/about', controller: controller, ncyBreadcrumb: { - label: "ABOUT" + label: N_("ABOUT") }, onExit: function(){ // hacky way to handle user browsing away via URL bar diff --git a/awx/ui/client/src/access/add-rbac-resource/rbac-resource.partial.html b/awx/ui/client/src/access/add-rbac-resource/rbac-resource.partial.html index 5cd8e19b1e..c9ca9c5e51 100644 --- a/awx/ui/client/src/access/add-rbac-resource/rbac-resource.partial.html +++ b/awx/ui/client/src/access/add-rbac-resource/rbac-resource.partial.html @@ -23,10 +23,10 @@ 1 -
+
Please select Users / Teams from the lists below.
-
+
Please select Users from the list below.
@@ -34,12 +34,12 @@
+ ng-class="{'is-selected': usersSelected }" translate> Users
+ ng-class="{'is-selected': teamsSelected }" translate> Teams
@@ -59,7 +59,7 @@ 2 - Please assign roles to the selected users/teams + Please assign roles to the selected users/teams
diff --git a/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.partial.html b/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.partial.html index bc30eff1b7..f162e28c58 100644 --- a/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.partial.html +++ b/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.partial.html @@ -26,7 +26,7 @@ 1 -
+
Please select resources from the lists below.
@@ -34,30 +34,30 @@
+ ng-class="{'is-selected': tab.job_templates }" translate> Job Templates
+ translate> Workflow Templates
+ ng-class="{'is-selected': tab.projects }" translate> Projects
+ translate> Inventories
+ translate> Credentials
@@ -86,10 +86,10 @@ 2 - Please assign roles to the selected resources + Please assign roles to the selected resources
+ ng-click="toggleKeyPane()" translate> Key
@@ -97,34 +97,34 @@
+ ng-show="showSection2Tab('job_templates')" translate> Job Templates
+ ng-show="showSection2Tab('workflow_templates')" translate> Workflow Templates
+ translate> Projects
+ translate> Inventories
+ translate> Credentials
@@ -170,13 +170,13 @@
diff --git a/awx/ui/client/src/access/rbac-multiselect/permissionsTeams.list.js b/awx/ui/client/src/access/rbac-multiselect/permissionsTeams.list.js index 8986478e85..dd05b4b0cc 100644 --- a/awx/ui/client/src/access/rbac-multiselect/permissionsTeams.list.js +++ b/awx/ui/client/src/access/rbac-multiselect/permissionsTeams.list.js @@ -5,7 +5,7 @@ *************************************************/ - export default function() { + export default ['i18n', function(i18n) { return { searchSize: 'col-lg-12 col-md-12 col-sm-12 col-xs-12', name: 'teams', @@ -15,19 +15,20 @@ multiSelectExtended: true, index: false, hover: true, - emptyListText : 'No Teams exist', + emptyListText : i18n._('No Teams exist'), fields: { name: { key: true, - label: 'name' + label: i18n._('name') }, organization: { - label: 'organization', + label: i18n._('organization'), ngBind: 'team.summary_fields.organization.name', sourceModel: 'organization', - sourceField: 'name' + sourceField: 'name', + searchable: true } } }; -} +}]; diff --git a/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js b/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js index 58a5605281..9769df3506 100644 --- a/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js +++ b/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js @@ -5,7 +5,7 @@ *************************************************/ - export default function() { + export default ['i18n', function(i18n) { return { name: 'users', iterator: 'user', @@ -21,22 +21,22 @@ multiSelectExtended: true, index: false, hover: true, - emptyListText : 'No Users exist', + emptyListText : i18n._('No Users exist'), fields: { first_name: { - label: 'First Name', + label: i18n._('First Name'), columnClass: 'col-md-3 col-sm-3 hidden-xs' }, last_name: { - label: 'Last Name', + label: i18n._('Last Name'), columnClass: 'col-md-3 col-sm-3 hidden-xs' }, username: { key: true, - label: 'Username', + label: i18n._('Username'), columnClass: 'col-md-5 col-sm-5 col-xs-11' }, }, }; -} +}]; diff --git a/awx/ui/client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js b/awx/ui/client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js index 99e3a1d8ed..f5276dbc12 100644 --- a/awx/ui/client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js +++ b/awx/ui/client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js @@ -8,7 +8,8 @@ export default [ 'CreateSelect2', - function(CreateSelect2) { + 'i18n', + function(CreateSelect2, i18n) { return { restrict: 'E', scope: { @@ -21,7 +22,7 @@ export default CreateSelect2({ element: '.roleSelect2', multiple: true, - placeholder: 'Select roles' + placeholder: i18n._('Select roles') }); } }; diff --git a/awx/ui/client/src/activity-stream/activitystream.route.js b/awx/ui/client/src/activity-stream/activitystream.route.js index 73877d5f1b..5b99ce55bd 100644 --- a/awx/ui/client/src/activity-stream/activitystream.route.js +++ b/awx/ui/client/src/activity-stream/activitystream.route.js @@ -4,6 +4,8 @@ * All Rights Reserved *************************************************/ + import { N_ } from '../i18n'; + export default { name: 'activityStream', route: '/activity_stream?target&id', @@ -22,7 +24,7 @@ export default { } }, ncyBreadcrumb: { - label: "ACTIVITY STREAM" + label: N_("ACTIVITY STREAM") }, onExit: function() { $('#stream-detail-modal').modal('hide'); diff --git a/awx/ui/client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html b/awx/ui/client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html index 67e4452ebc..9735fd6e17 100644 --- a/awx/ui/client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html +++ b/awx/ui/client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html @@ -9,15 +9,15 @@ diff --git a/awx/ui/client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js b/awx/ui/client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js index dc6c4a819d..c8cfc37147 100644 --- a/awx/ui/client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js +++ b/awx/ui/client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js @@ -4,7 +4,7 @@ * All Rights Reserved *************************************************/ -export default ['templateUrl', function(templateUrl) { +export default ['templateUrl', 'i18n', function(templateUrl, i18n) { return { restrict: 'E', scope: true, @@ -15,18 +15,18 @@ export default ['templateUrl', function(templateUrl) { $scope.streamTarget = ($state.params && $state.params.target) ? $state.params.target : 'dashboard'; $scope.options = [ - {label: 'All Activity', value: 'dashboard'}, - {label: 'Credentials', value: 'credential'}, - {label: 'Hosts', value: 'host'}, - {label: 'Inventories', value: 'inventory'}, - {label: 'Inventory Scripts', value: 'inventory_script'}, - {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: i18n._('All Activity'), value: 'dashboard'}, + {label: i18n._('Credentials'), value: 'credential'}, + {label: i18n._('Hosts'), value: 'host'}, + {label: i18n._('Inventories'), value: 'inventory'}, + {label: i18n._('Inventory Scripts'), value: 'inventory_script'}, + {label: i18n._('Jobs'), value: 'job'}, + {label: i18n._('Organizations'), value: 'organization'}, + {label: i18n._('Projects'), value: 'project'}, + {label: i18n._('Schedules'), value: 'schedule'}, + {label: i18n._('Teams'), value: 'team'}, + {label: i18n._('Templates'), value: 'template'}, + {label: i18n._('Users'), value: 'user'} ]; CreateSelect2({ diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 577ce739b8..4cf399699d 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -99,6 +99,8 @@ var tower = angular.module('Tower', [ require('angular-tz-extensions'), require('lr-infinite-scroll'), require('ng-toast'), + 'gettext', + 'I18N', uiRouter, 'ui.router.state.events', @@ -201,8 +203,6 @@ var tower = angular.module('Tower', [ scheduler.name, 'ApiModelHelper', 'ActivityStreamHelper', - 'gettext', - 'I18N', 'WorkflowFormDefinition', 'InventorySourcesListDefinition', 'WorkflowMakerFormDefinition' @@ -290,6 +290,9 @@ var tower = angular.module('Tower', [ "jobs": ["status_changed"] } } + }, + ncyBreadcrumb: { + label: N_('PROJECTS') } }) }); @@ -371,12 +374,12 @@ var tower = angular.module('Tower', [ 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest', 'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService', - 'FeaturesService', '$filter', 'SocketService', 'I18NInit', + 'FeaturesService', '$filter', 'SocketService', function($stateExtender, $q, $compile, $cookieStore, $rootScope, $log, $stateParams, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, LoadConfig, Store, pendoService, Prompt, Rest, Wait, ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService, - $filter, SocketService, I18NInit) { + $filter, SocketService) { $rootScope.$state = $state; $rootScope.$state.matches = function(stateName) { @@ -388,7 +391,6 @@ var tower = angular.module('Tower', [ $log.debug(`$state.defaultErrorHandler: ${error}`); }); - I18NInit(); $stateExtender.addState({ name: 'dashboard', url: '/home', diff --git a/awx/ui/client/src/bread-crumb/bread-crumb.block.less b/awx/ui/client/src/bread-crumb/bread-crumb.block.less index e0abee7832..e2254f6fa2 100644 --- a/awx/ui/client/src/bread-crumb/bread-crumb.block.less +++ b/awx/ui/client/src/bread-crumb/bread-crumb.block.less @@ -73,6 +73,10 @@ vertical-align: bottom; } +.BreadCrumb-invItem { + max-width: 400px; +} + .BreadCrumb-item + .BreadCrumb-item:before { content: "/"; padding: 0 5px; diff --git a/awx/ui/client/src/bread-crumb/bread-crumb.directive.js b/awx/ui/client/src/bread-crumb/bread-crumb.directive.js index 3c64a0b701..979ebd69d5 100644 --- a/awx/ui/client/src/bread-crumb/bread-crumb.directive.js +++ b/awx/ui/client/src/bread-crumb/bread-crumb.directive.js @@ -1,6 +1,6 @@ export default - ['templateUrl', '$state', 'FeaturesService', 'ProcessErrors','$rootScope', 'Store', 'Empty', '$window', 'BreadCrumbService', - function(templateUrl, $state, FeaturesService, ProcessErrors, $rootScope, Store, Empty, $window, BreadCrumbService) { + ['templateUrl', '$state', 'FeaturesService', 'ProcessErrors','$rootScope', 'Store', 'Empty', '$window', 'BreadCrumbService', 'i18n', + function(templateUrl, $state, FeaturesService, ProcessErrors, $rootScope, Store, Empty, $window, BreadCrumbService, i18n) { return { restrict: 'E', templateUrl: templateUrl('bread-crumb/bread-crumb'), @@ -103,7 +103,7 @@ export default if(features){ scope.loadingLicense = false; scope.activityStreamActive = (toState.name === 'activityStream') ? true : false; - scope.activityStreamTooltip = (toState.name === 'activityStream') ? 'Hide Activity Stream' : 'View Activity Stream'; + scope.activityStreamTooltip = (toState.name === 'activityStream') ? i18n._('Hide Activity Stream') : i18n._('View Activity Stream'); scope.showActivityStreamButton = (FeaturesService.featureEnabled('activity_streams') || toState.name ==='activityStream') ? true : false; } } diff --git a/awx/ui/client/src/configuration/auth-form/configuration-auth.partial.html b/awx/ui/client/src/configuration/auth-form/configuration-auth.partial.html index 71192e17c6..8004975a34 100644 --- a/awx/ui/client/src/configuration/auth-form/configuration-auth.partial.html +++ b/awx/ui/client/src/configuration/auth-form/configuration-auth.partial.html @@ -1,6 +1,6 @@
-
Sub Category
+
Sub Category
@@ -173,10 +173,10 @@ @@ -194,8 +194,8 @@
- - + +
@@ -205,9 +205,9 @@ - - - + + +
PlaysStartedElapsedPlaysStartedElapsed
@@ -242,7 +242,7 @@
-
2 Please select a task below to view its associated hosts
+
2 Please select a task below to view its associated hosts
@@ -253,8 +253,8 @@
- - + +
@@ -263,10 +263,10 @@ - - - - + + + +
TasksStartedElapsedTasksStartedElapsed
@@ -304,19 +304,19 @@ {{ task.missingCount }}
- No matching hosts. + No matching hosts.
- Waiting... + Waiting... - Loading... + Loading... - No matching tasks + No matching tasks @@ -337,8 +337,8 @@
- - + +
@@ -346,9 +346,9 @@ - - - + + +
HostsItemMessageHostsItemMessage
@@ -365,13 +365,13 @@ {{ result.msg }} - Waiting... + Waiting... - Loading... + Loading... - No matching host events + No matching host events @@ -388,10 +388,10 @@ @@ -411,13 +411,13 @@
-
STANDARD OUT
+
STANDARD OUT
- - diff --git a/awx/ui/client/src/job-submission/job-submission-factories/launchjob.factory.js b/awx/ui/client/src/job-submission/job-submission-factories/launchjob.factory.js index 64c9344b19..d49b4e521d 100644 --- a/awx/ui/client/src/job-submission/job-submission-factories/launchjob.factory.js +++ b/awx/ui/client/src/job-submission/job-submission-factories/launchjob.factory.js @@ -1,6 +1,6 @@ export default - function LaunchJob(Rest, Wait, ProcessErrors, ToJSON, Empty, GetBasePath, $state, $location, $rootScope) { + function LaunchJob(Rest, Wait, ProcessErrors, ToJSON, Empty, GetBasePath, $state, $location, $rootScope, i18n) { // This factory gathers up all the job launch data and POST's it. @@ -163,8 +163,10 @@ export default } }) .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed updating job ' + scope.job_template_id + ' with variables. POST returned: ' + status }); + let template_id = scope.job_template_id; + template_id = (template_id === undefined) ? "undefined" : i18n.sprintf("%d", template_id); + ProcessErrors(scope, data, status, null, { hdr: i18n._('Error!'), + msg: i18n.sprintf(i18n._('Failed updating job %s with variables. POST returned: %d'), template_id, status) }); }); }; @@ -182,8 +184,8 @@ export default buildData(); }) .error(function (data, status) { - ProcessErrors(scope, data, status, { hdr: 'Error!', - msg: 'Failed to retrieve job template extra variables.' }); + ProcessErrors(scope, data, status, { hdr: i18n._('Error!'), + msg: i18n._('Failed to retrieve job template extra variables.') }); }); }; @@ -209,5 +211,6 @@ LaunchJob.$inject = 'GetBasePath', '$state', '$location', - '$rootScope' + '$rootScope', + 'i18n' ]; diff --git a/awx/ui/client/src/license/license.route.js b/awx/ui/client/src/license/license.route.js index 947820a6e1..78ab6e4348 100644 --- a/awx/ui/client/src/license/license.route.js +++ b/awx/ui/client/src/license/license.route.js @@ -5,6 +5,7 @@ *************************************************/ import {templateUrl} from '../shared/template-url/template-url.factory'; +import { N_ } from '../i18n'; export default { name: 'license', @@ -14,7 +15,7 @@ export default { data: {}, ncyBreadcrumb: { parent: 'setup', - label: 'LICENSE' + label: N_('LICENSE') }, resolve: { features: ['CheckLicense', '$rootScope', diff --git a/awx/ui/client/src/lists/AllJobs.js b/awx/ui/client/src/lists/AllJobs.js index d5e73c3982..4f09a4f501 100644 --- a/awx/ui/client/src/lists/AllJobs.js +++ b/awx/ui/client/src/lists/AllJobs.js @@ -13,7 +13,7 @@ export default name: 'jobs', basePath: 'unified_jobs', iterator: 'job', - editTitle: 'All Jobs', + editTitle: i18n._('All Jobs'), index: false, hover: true, well: false, @@ -42,13 +42,13 @@ export default noLink: true }, name: { - label: 'Name', + label: i18n._('Name'), columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-6', ngClick: "viewJobDetails(job)", badgePlacement: 'right', badgeCustom: true, badgeIcon: ` ` }, type: { - label: 'Type', + label: i18n._('Type'), ngBind: 'job.type_label', link: false, columnClass: "col-lg-2 hidden-md hidden-sm hidden-xs", columnShow: "showJobType", }, finished: { - label: 'Finished', + label: i18n._('Finished'), noLink: true, filter: "longDate", columnClass: "col-lg-2 col-md-3 col-sm-3 hidden-xs", @@ -73,7 +73,7 @@ export default desc: true }, labels: { - label: 'Labels', + label: i18n._('Labels'), type: 'labels', nosort: true, showDelete: false, @@ -91,28 +91,28 @@ export default "view": { mode: "all", ngClick: "viewJobDetails(job)", - awToolTip: "View the job", + awToolTip: i18n._("View the job"), dataPlacement: "top" }, submit: { icon: 'icon-rocket', mode: 'all', ngClick: 'relaunchJob($event, job.id)', - awToolTip: 'Relaunch using the same parameters', + awToolTip: i18n._('Relaunch using the same parameters'), dataPlacement: 'top', ngShow: "!(job.type == 'system_job') && job.summary_fields.user_capabilities.start" }, cancel: { mode: 'all', ngClick: 'deleteJob(job.id)', - awToolTip: 'Cancel the job', + awToolTip: i18n._('Cancel the job'), dataPlacement: 'top', ngShow: "(job.status === 'running'|| job.status === 'waiting' || job.status === 'pending') && job.summary_fields.user_capabilities.start" }, "delete": { mode: 'all', ngClick: 'deleteJob(job.id)', - awToolTip: 'Delete the job', + awToolTip: i18n._('Delete the job'), dataPlacement: 'top', ngShow: "(job.status !== 'running' && job.status !== 'waiting' && job.status !== 'pending') && job.summary_fields.user_capabilities.delete" } diff --git a/awx/ui/client/src/lists/JobEvents.js b/awx/ui/client/src/lists/JobEvents.js index 9327ced8da..742fa354b6 100644 --- a/awx/ui/client/src/lists/JobEvents.js +++ b/awx/ui/client/src/lists/JobEvents.js @@ -7,11 +7,12 @@ export default angular.module('JobEventsListDefinition', []) - .value('JobEventList', { + .factory('JobEventList', ['i18n', function(i18n) { + return { name: 'jobevents', iterator: 'jobevent', - editTitle: 'Job Events', + editTitle: i18n._('Job Events'), index: false, hover: true, "class": "condensed", @@ -27,27 +28,27 @@ export default //}, events: { href: '/#/job_events/{{ job_id }}', - label: 'Events', + label: i18n._('Events'), active: true, icon: 'icon-list-ul' }, hosts: { href: '/#/job_host_summaries/{{ job_id }}', - label: 'Host Summary', + label: i18n._('Host Summary'), icon: 'icon-laptop' } }, fields: { created: { - label: 'Created On', + label: i18n._('Created On'), columnClass: 'col-lg-1 col-md-1 hidden-sm hidden-xs', key: true, nosort: true, noLink: true }, status: { - label: 'Status', + label: i18n._('Status'), showValue: false, columnClass: 'col-sm-1 col-xs-2 text-center', nosort: true, @@ -61,7 +62,7 @@ export default badgeNgClick: 'viewJobEvent(jobevent.id)' }, event_display: { - label: 'Event', + label: i18n._('Event'), hasChildren: true, ngClick: 'toggleChildren(jobevent.id, jobevent.related.children)', nosort: true, @@ -69,7 +70,7 @@ export default appendHTML: 'jobevent.event_detail' }, host: { - label: 'Host', + label: i18n._('Host'), ngBind: 'jobevent.summary_fields.host.name', ngHref: '{{ jobevent.hostLink }}', nosort: true, @@ -85,7 +86,7 @@ export default awToolTip: 'Refresh the page', ngClick: 'refresh()', actionClass: 'btn List-buttonDefault', - buttonContent: 'REFRESH' + buttonContent: i18n._('REFRESH') } }, @@ -94,10 +95,10 @@ export default columnClass: 'col-sm-1 col-xs-2', view: { - label: 'View', + label: i18n._('View'), ngClick: 'viewJobEvent(jobevent.id)', - awToolTip: 'View event details', + awToolTip: i18n._('View event details'), dataPlacement: 'top' } } - }); + };}]); diff --git a/awx/ui/client/src/lists/Schedules.js b/awx/ui/client/src/lists/Schedules.js index ef1d7072bc..818863aa78 100644 --- a/awx/ui/client/src/lists/Schedules.js +++ b/awx/ui/client/src/lists/Schedules.js @@ -7,7 +7,8 @@ export default angular.module('SchedulesListDefinition', []) - .value('SchedulesList', { + .factory('StreamList', ['i18n', function(i18n) { + return { name: 'schedules', iterator: 'schedule', @@ -31,22 +32,22 @@ export default }, name: { key: true, - label: 'Name', + label: i18n._('Name'), ngClick: "editSchedule(schedule)", columnClass: "col-md-3 col-sm-3 col-xs-6" }, dtstart: { - label: 'First Run', + label: i18n._('First Run'), filter: "longDate", columnClass: "List-staticColumn--schedulerTime hidden-sm hidden-xs" }, next_run: { - label: 'Next Run', + label: i18n._('Next Run'), filter: "longDate", columnClass: "List-staticColumn--schedulerTime hidden-xs" }, dtend: { - label: 'Final Run', + label: i18n._('Final Run'), filter: "longDate", columnClass: "List-staticColumn--schedulerTime hidden-xs" }, @@ -55,45 +56,45 @@ export default actions: { refresh: { mode: 'all', - awToolTip: "Refresh the page", + awToolTip: i18n._("Refresh the page"), ngClick: "refreshSchedules()", actionClass: 'btn List-buttonDefault', ngShow: "socketStatus == 'error'", - buttonContent: 'REFRESH' + buttonContent: i18n._('REFRESH') }, add: { mode: 'all', ngClick: 'addSchedule()', - awToolTip: 'Add a new schedule', + awToolTip: i18n._('Add a new schedule'), actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD', + buttonContent: '+ ' + i18n._('ADD'), ngShow: 'canAdd' } }, fieldActions: { edit: { - label: 'Edit', + label: i18n._('Edit'), ngClick: "editSchedule(schedule)", icon: 'icon-edit', - awToolTip: 'Edit schedule', + awToolTip: i18n._('Edit schedule'), dataPlacement: 'top', ngShow: 'schedule.summary_fields.user_capabilities.edit' }, view: { - label: 'View', + label: i18n._('View'), ngClick: "editSchedule(schedule)", - awToolTip: 'View schedule', + awToolTip: i18n._('View schedule'), dataPlacement: 'top', ngShow: '!schedule.summary_fields.user_capabilities.edit' }, "delete": { - label: 'Delete', + label: i18n._('Delete'), ngClick: "deleteSchedule(schedule.id)", icon: 'icon-trash', - awToolTip: 'Delete schedule', + awToolTip: i18n._('Delete schedule'), dataPlacement: 'top', ngShow: 'schedule.summary_fields.user_capabilities.delete' } } - }); + };}]); diff --git a/awx/ui/client/src/lists/Streams.js b/awx/ui/client/src/lists/Streams.js index 34e0652885..bb2258a22e 100644 --- a/awx/ui/client/src/lists/Streams.js +++ b/awx/ui/client/src/lists/Streams.js @@ -7,15 +7,16 @@ export default angular.module('StreamListDefinition', []) - .value('StreamList', { + .factory('StreamList', ['i18n', function(i18n) { + return { name: 'activities', iterator: 'activity', basePath: 'activity_stream', - editTitle: 'Activity Stream', - listTitle: 'Activity Stream
{{streamSubTitle}}', + editTitle: i18n._('Activity Stream'), + listTitle: i18n._('Activity Stream') + '
{{streamSubTitle}}', listTitleBadge: false, - emptyListText: 'There are no events to display at this time', + emptyListText: i18n._('There are no events to display at this time'), selectInstructions: '', index: false, hover: true, @@ -24,7 +25,7 @@ export default fields: { timestamp: { - label: 'Time', + label: i18n._('Time'), key: true, desc: true, noLink: true, @@ -32,14 +33,14 @@ export default columnClass: 'col-lg-3 col-md-2 col-sm-3 col-xs-3' }, user: { - label: 'Initiated by', + label: i18n._('Initiated by'), ngBindHtml: 'activity.user', // @todo punch monkey sourceModel: 'actor', sourceField: 'username', columnClass: 'col-lg-3 col-md-3 col-sm-3 col-xs-3' }, description: { - label: 'Event', + label: i18n._('Event'), ngBindHtml: 'activity.description', // @todo punch monkey nosort: true, columnClass: 'ActivityStream-eventColumnHeader col-lg-5 col-md-6 col-sm-4 col-xs-4' @@ -50,10 +51,10 @@ export default refresh: { mode: 'all', id: 'activity-stream-refresh-btn', - awToolTip: "Refresh the page", + awToolTip: i18n._("Refresh the page"), ngClick: "refreshStream()", actionClass: 'btn List-buttonDefault ActivityStream-refreshButton', - buttonContent: 'REFRESH' + buttonContent: i18n._('REFRESH') } }, @@ -62,13 +63,13 @@ export default columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2', view: { - label: 'View', + label: i18n._('View'), ngClick: "showDetail(activity.id)", icon: 'fa-zoom-in', "class": 'btn-default btn-xs', - awToolTip: 'View event details', + awToolTip: i18n._('View event details'), dataPlacement: 'top' } } - }); + };}]); diff --git a/awx/ui/client/src/login/authenticationServices/timer.factory.js b/awx/ui/client/src/login/authenticationServices/timer.factory.js index f68d0e412a..ebdf440baf 100644 --- a/awx/ui/client/src/login/authenticationServices/timer.factory.js +++ b/awx/ui/client/src/login/authenticationServices/timer.factory.js @@ -23,9 +23,9 @@ */ export default ['$rootScope', '$cookieStore', 'CreateDialog', 'Authorization', - 'Store', '$interval', '$state', '$q', + 'Store', '$interval', '$state', '$q', 'i18n', function ($rootScope, $cookieStore, CreateDialog, Authorization, - Store, $interval, $state, $q) { + Store, $interval, $state, $q, i18n) { return { sessionTime: null, @@ -154,7 +154,7 @@ export default }); CreateDialog({ id: 'idle-modal' , - title: "Idle Session", + title: i18n._("Idle Session"), scope: $rootScope, buttons: buttons, width: 470, diff --git a/awx/ui/client/src/login/loginModal/loginModal.partial.html b/awx/ui/client/src/login/loginModal/loginModal.partial.html index d6e30a20a3..eb124adcf4 100644 --- a/awx/ui/client/src/login/loginModal/loginModal.partial.html +++ b/awx/ui/client/src/login/loginModal/loginModal.partial.html @@ -86,7 +86,7 @@
-
NOTICE
{{ customLoginInfo | sanitize }}
+
NOTICE
{{ customLoginInfo | sanitize }}
stateDefinitions.generateTree({ parent: 'notifications', // top-most node in the generated tree @@ -84,7 +85,7 @@ angular.module('notifications', [ }, ncyBreadcrumb: { parent: 'setup', - name: 'NOTIFICATIONS' + label: N_('NOTIFICATIONS') } }) }); diff --git a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js index 208c4a3b8d..d3aec68845 100644 --- a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js +++ b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js @@ -7,10 +7,12 @@ export default ['$rootScope', '$scope', 'Wait', 'generateList', 'NotificationTemplatesList', 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', 'GetChoices', 'Empty', 'Find', 'ngToast', '$compile', '$filter', 'Dataset', 'rbacUiControlService', + 'i18n', function( $rootScope, $scope, Wait, GenerateList, NotificationTemplatesList, GetBasePath, Rest, ProcessErrors, Prompt, $state, GetChoices, - Empty, Find, ngToast, $compile, $filter, Dataset, rbacUiControlService) { + Empty, Find, ngToast, $compile, $filter, Dataset, rbacUiControlService, + i18n) { var defaultUrl = GetBasePath('notification_templates'), list = NotificationTemplatesList; @@ -68,8 +70,8 @@ html = "\n"; html += "\n"; html += ""; - html += ""; - html += ""; + html += ""; + html += ""; html += "\n"; html += "\n"; html += "\n"; @@ -83,7 +85,7 @@ html += "\n"; html += "
StatusTime" + i18n._("Status") + "" + i18n._("Time") + "
\n"; } else { - html = "

No recent notifications.

\n"; + html = "

" + i18n._("No recent notifications.") + "

\n"; } notification_template.template_status_html = html; } @@ -110,7 +112,7 @@ }) .catch(function() { ngToast.danger({ - content: ` ${name}: Notification Failed.`, + content: ` ${name}: ` + i18n._('Notification Failed.'), }); }); @@ -179,12 +181,12 @@ }); }); }; - var bodyHtml = '
Are you sure you want to delete the notification template below?
' + $filter('sanitize')(name) + '
'; + var bodyHtml = '
' + i18n._('Are you sure you want to delete the notification template below?') + '
' + $filter('sanitize')(name) + '
'; Prompt({ - hdr: 'Delete', + hdr: i18n._('Delete'), body: bodyHtml, action: action, - actionText: 'DELETE' + actionText: i18n._('DELETE') }); }; } diff --git a/awx/ui/client/src/notifications/notificationTemplates.form.js b/awx/ui/client/src/notifications/notificationTemplates.form.js index e115caf709..66e9a9854e 100644 --- a/awx/ui/client/src/notifications/notificationTemplates.form.js +++ b/awx/ui/client/src/notifications/notificationTemplates.form.js @@ -16,6 +16,9 @@ export default ['i18n', function(i18n) { addTitle: i18n._('New Notification Template'), editTitle: '{{ name }}', name: 'notification_template', + // I18N for "CREATE NOTIFICATION_TEMPLATE" + // on /#/notification_templates/add + breadcrumbName: i18n._('NOTIFICATION TEMPLATE'), stateTree: 'notifications', basePath: 'notification_templates', showActions: true, @@ -389,19 +392,19 @@ export default ['i18n', function(i18n) { ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)' }, email_options: { - label: 'Options', + label: i18n._('Options'), type: 'radio_group', subForm: 'typeSubForm', ngShow: "notification_type.value == 'email'", ngChange: "emailOptionsChange()", options: [{ value: 'use_tls', - label: 'Use TLS', + label: i18n._('Use TLS'), ngShow: "notification_type.value == 'email' ", labelClass: 'NotificationsForm-radioButtons' }, { value: 'use_ssl', - label: 'Use SSL', + label: i18n._('Use SSL'), ngShow: "notification_type.value == 'email'", labelClass: 'NotificationsForm-radioButtons' }] diff --git a/awx/ui/client/src/notifications/notificationTemplates.list.js b/awx/ui/client/src/notifications/notificationTemplates.list.js index 92324c8701..70b9e21921 100644 --- a/awx/ui/client/src/notifications/notificationTemplates.list.js +++ b/awx/ui/client/src/notifications/notificationTemplates.list.js @@ -23,7 +23,7 @@ export default ['i18n', function(i18n){ nosort: true, icon: 'icon-job-{{ notification_template.status }}', awPopOver: '{{ notification_template.template_status_html }}', - dataTitle: "Recent Notifications", + dataTitle: i18n._("Recent Notifications"), dataPlacement: 'right', columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumn--smallStatus' }, diff --git a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html index df0d5233c6..a8a6cbbb81 100644 --- a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html +++ b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html @@ -5,7 +5,7 @@
-
{{ $parent.organization_name }}
Add {{ addType | capitalize}} +
{{ $parent.organization_name }}
Add {{ addType | capitalize}}
diff --git a/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js b/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js index ceb8a45251..517e37c8c0 100644 --- a/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js +++ b/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js @@ -10,6 +10,7 @@ import OrganizationsJobTemplates from './controllers/organizations-job-templates import OrganizationsProjects from './controllers/organizations-projects.controller'; import OrganizationsTeams from './controllers/organizations-teams.controller'; import OrganizationsUsers from './controllers/organizations-users.controller'; +import { N_ } from '../../i18n'; export default [{ name: 'organizations.users', @@ -55,7 +56,7 @@ export default [{ }, ncyBreadcrumb: { parent: "organizations.edit", - label: "USERS" + label: N_("USERS") }, data: { @@ -128,7 +129,7 @@ export default [{ }, ncyBreadcrumb: { parent: "organizations.edit", - label: "TEAMS" + label: N_("TEAMS") }, resolve: { features: ['FeaturesService', function(FeaturesService) { @@ -174,7 +175,7 @@ export default [{ }, ncyBreadcrumb: { parent: "organizations.edit", - label: "INVENTORIES" + label: N_("INVENTORIES") }, resolve: { features: ['FeaturesService', function(FeaturesService) { @@ -225,7 +226,7 @@ export default [{ }, ncyBreadcrumb: { parent: "organizations.edit", - label: "PROJECTS" + label: N_("PROJECTS") }, resolve: { features: ['FeaturesService', function(FeaturesService) { @@ -283,7 +284,7 @@ export default [{ }, ncyBreadcrumb: { parent: "organizations.edit", - label: "JOB TEMPLATES" + label: N_("JOB TEMPLATES") }, resolve: { features: ['FeaturesService', function(FeaturesService) { @@ -359,7 +360,7 @@ export default [{ }, ncyBreadcrumb: { parent: "organizations.edit", - label: "ADMINS" + label: N_("ADMINS") }, resolve: { features: ['FeaturesService', function(FeaturesService) { diff --git a/awx/ui/client/src/organizations/list/organizations-list.controller.js b/awx/ui/client/src/organizations/list/organizations-list.controller.js index 3849c123a4..a718db2548 100644 --- a/awx/ui/client/src/organizations/list/organizations-list.controller.js +++ b/awx/ui/client/src/organizations/list/organizations-list.controller.js @@ -7,10 +7,10 @@ export default ['$stateParams', '$scope', '$rootScope', '$location', '$log', '$compile', 'Rest', 'OrganizationList', 'Alert', 'Prompt', 'ClearScope', - 'ProcessErrors', 'GetBasePath', 'Wait', '$state', 'rbacUiControlService', '$filter', 'Dataset', + 'ProcessErrors', 'GetBasePath', 'Wait', '$state', 'rbacUiControlService', '$filter', 'Dataset', 'i18n', function($stateParams, $scope, $rootScope, $location, $log, $compile, Rest, OrganizationList, Alert, Prompt, ClearScope, - ProcessErrors, GetBasePath, Wait, $state, rbacUiControlService, $filter, Dataset) { + ProcessErrors, GetBasePath, Wait, $state, rbacUiControlService, $filter, Dataset, i18n) { ClearScope(); @@ -162,10 +162,10 @@ export default ['$stateParams', '$scope', '$rootScope', '$location', }; Prompt({ - hdr: 'Delete', - body: '
Are you sure you want to delete the organization below?
' + $filter('sanitize')(name) + '
', + hdr: i18n._('Delete'), + body: '
' + i18n._('Are you sure you want to delete the organization below?') + '
' + $filter('sanitize')(name) + '
', action: action, - actionText: 'DELETE' + actionText: i18n._('DELETE') }); }; } diff --git a/awx/ui/client/src/organizations/main.js b/awx/ui/client/src/organizations/main.js index fac6a179e9..076c89d1aa 100644 --- a/awx/ui/client/src/organizations/main.js +++ b/awx/ui/client/src/organizations/main.js @@ -10,6 +10,7 @@ import OrganizationsAdd from './add/organizations-add.controller'; import OrganizationsEdit from './edit/organizations-edit.controller'; import organizationsLinkout from './linkout/main'; import OrganizationsLinkoutStates from './linkout/organizations-linkout.route'; +import { N_ } from '../i18n'; export default @@ -48,7 +49,7 @@ angular.module('Organizations', [ }, ncyBreadcrumb: { parent: 'setup', - label: 'ORGANIZATIONS' + label: N_('ORGANIZATIONS') }, // concat manually-defined state definitions with generated defintions }).then((generated) => { diff --git a/awx/ui/client/src/partials/logviewer.html b/awx/ui/client/src/partials/logviewer.html index 59fe6ca045..e3c188010b 100644 --- a/awx/ui/client/src/partials/logviewer.html +++ b/awx/ui/client/src/partials/logviewer.html @@ -1,12 +1,12 @@
- CLEAR ALL + CLEAR ALL
@@ -37,7 +37,7 @@
- EXAMPLES: + EXAMPLES:
@@ -45,13 +45,13 @@
- FIELDS: {{ key }}, + FIELDS: {{ key }},
- RELATED FIELDS: {{ relation }}, + RELATED FIELDS: {{ relation }},
- ADDITIONAL INFORMATION: For additional information on advanced search search syntax please see the Ansible Tower documentation. + ADDITIONAL INFORMATION: For additional information on advanced search search syntax please see the Ansible Tower documentation.
diff --git a/awx/ui/client/src/shared/stateDefinitions.factory.js b/awx/ui/client/src/shared/stateDefinitions.factory.js index 8279173dc9..4ebe121a9b 100644 --- a/awx/ui/client/src/shared/stateDefinitions.factory.js +++ b/awx/ui/client/src/shared/stateDefinitions.factory.js @@ -9,7 +9,7 @@ * generateLookupNodes - Attaches to a form node. Builds an abstract '*.lookup' node with field-specific 'lookup.*' children e.g. {name: 'projects.add.lookup.organizations', ...} */ -export default ['$injector', '$stateExtender', '$log', function($injector, $stateExtender, $log) { +export default ['$injector', '$stateExtender', '$log', 'i18n', function($injector, $stateExtender, $log, i18n) { return { /** * @ngdoc method @@ -150,7 +150,7 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat url: url, ncyBreadcrumb: { [params.parent ? 'parent' : null]: `${params.parent}`, - label: `CREATE ${form.breadcrumbName || form.name}` + label: i18n.sprintf(i18n._("CREATE %s"), i18n._(`${form.breadcrumbName || form.name}`)) }, views: { 'form': { @@ -274,7 +274,7 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat }, views: { [`modal@${formStateDefinition.name}`]: { - template: `` + template: `` } }, resolve: { @@ -339,7 +339,7 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat }, views: { [`modal@${formStateDefinition.name}`]: { - template: `` + template: `` } }, resolve: { @@ -492,7 +492,7 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat // } return state; } - + function buildRbacUserDirective() { let states = []; @@ -508,7 +508,7 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat }, views: { [`modal@${formStateDefinition.name}`]: { - template: `` + template: `` } }, resolve: { diff --git a/awx/ui/client/src/smart-status/smart-status.block.less b/awx/ui/client/src/smart-status/smart-status.block.less index 9ce9c7dc01..633c5183ff 100644 --- a/awx/ui/client/src/smart-status/smart-status.block.less +++ b/awx/ui/client/src/smart-status/smart-status.block.less @@ -26,6 +26,10 @@ padding: 0px; } +.SmartStatus--failed:before { + content: "\f06a"; +} + .SmartStatus--running{ color: @default-icon; margin-top: 10px; diff --git a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html index 69e3c40b66..eff50b6290 100644 --- a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html +++ b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html @@ -4,7 +4,7 @@
-
+
RESULTS
@@ -16,12 +16,12 @@
-
Name
+
Name
{{ job.module_name }}
-
STATUS
+
STATUS
{{ job.status }} @@ -29,54 +29,54 @@
-
STARTED
+
STARTED
{{ job.started | longDate }}
-
FINISHED
+
FINISHED
{{ job.finished | longDate }}
-
ELAPSED
+
ELAPSED
{{ job.elapsed }} seconds
-
Module Args
+
Module Args
{{ job.module_args }}
-
Inventory
+
Inventory
-
Credential
+
Credential
-
Launched By
+
Launched By
@@ -84,19 +84,19 @@
-
Forks
+
Forks
{{ forks }}
-
Limit
+
Limit
{{ limit }}
-
Verbosity
+
Verbosity
{{ verbosity }}
@@ -105,13 +105,13 @@
-
STANDARD OUT
+
STANDARD OUT
- diff --git a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html index d06a66dd1b..0f398643b9 100644 --- a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html +++ b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html @@ -4,7 +4,7 @@
-
+
RESULTS
@@ -16,13 +16,13 @@
-
NAME
+
NAME
{{ inventory_source_name }}
-
STATUS
+
STATUS
{{ job.status }} @@ -42,42 +42,42 @@
-
LICENSE ERROR
+
LICENSE ERROR
{{ job.license_error }}
-
STARTED
+
STARTED
{{ job.started | longDate }}
-
FINISHED
+
FINISHED
{{ job.finished | longDate }}
-
ELAPSED
+
ELAPSED
{{ job.elapsed }} seconds
-
LAUNCH TYPE
+
LAUNCH TYPE
{{ job.launch_type }}
-
CREDENTIAL
+
CREDENTIAL
-
GROUP
+
GROUP
-
SOURCE
+
SOURCE
{{ source }}
-
REGIONS
+
REGIONS
{{ source_regions }}
-
OVERWRITE
+
OVERWRITE
{{ job.overwrite }}
-
OVERWRITE VARS
+
OVERWRITE VARS
{{ job.overwrite_vars }}
@@ -128,13 +128,13 @@
-
STANDARD OUT
+
STANDARD OUT
- diff --git a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html index 0f24a79aec..62d7b6045d 100644 --- a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html +++ b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html @@ -4,25 +4,25 @@
-
+
RESULTS
- - - + + +
-
NAME
+
NAME
{{ project_name }}
-
STATUS
+
STATUS
{{ job.status }} @@ -42,35 +42,35 @@
-
STARTED
+
STARTED
{{ job.started | longDate }}
-
FINISHED
+
FINISHED
{{ job.finished | longDate }}
-
ELAPSED
+
ELAPSED
{{ job.elapsed }} seconds
-
LAUNCH TYPE
+
LAUNCH TYPE
{{ job.launch_type }}
-
PROJECT
+
PROJECT
-
CREDENTIAL
+
CREDENTIAL
{{ credential_name }} @@ -93,13 +93,13 @@
-
STANDARD OUT
+
STANDARD OUT
- diff --git a/awx/ui/client/src/system-tracking/system-tracking.route.js b/awx/ui/client/src/system-tracking/system-tracking.route.js index 6875df68fa..da803afc91 100644 --- a/awx/ui/client/src/system-tracking/system-tracking.route.js +++ b/awx/ui/client/src/system-tracking/system-tracking.route.js @@ -5,6 +5,7 @@ *************************************************/ import {templateUrl} from '../shared/template-url/template-url.factory'; +import { N_ } from '../i18n'; export default { name: 'systemTracking', @@ -14,7 +15,7 @@ export default { params: {hosts: null, inventory: null}, reloadOnSearch: false, ncyBreadcrumb: { - label: "SYSTEM TRACKING" + label: N_("SYSTEM TRACKING") }, resolve: { moduleOptions: diff --git a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js b/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js index 07d72a615d..d2ac02e66e 100644 --- a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js +++ b/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js @@ -9,13 +9,13 @@ '$stateParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'ClearScope', 'GetBasePath', 'md5Setup', 'ParseTypeChange', 'Wait', 'Empty', 'ToJSON', 'CallbackHelpInit', 'Prompt', 'GetChoices', '$state', - 'CreateSelect2', '$q', + 'CreateSelect2', '$q', 'i18n', function( $filter, $scope, $rootScope, $compile, $location, $log, $stateParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, ClearScope, GetBasePath, md5Setup, ParseTypeChange, Wait, Empty, ToJSON, CallbackHelpInit, Prompt, GetChoices, - $state, CreateSelect2, $q + $state, CreateSelect2, $q, i18n ) { Rest.setUrl(GetBasePath('job_templates')); @@ -23,7 +23,7 @@ .success(function(data) { if (!data.actions.POST) { $state.go("^"); - Alert('Permission Error', 'You do not have permission to add a job template.', 'alert-info'); + Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a job template.'), 'alert-info'); } }); diff --git a/awx/ui/client/src/templates/list/templates-list.controller.js b/awx/ui/client/src/templates/list/templates-list.controller.js index 7ed77de7d4..a308a4c3ca 100644 --- a/awx/ui/client/src/templates/list/templates-list.controller.js +++ b/awx/ui/client/src/templates/list/templates-list.controller.js @@ -77,7 +77,7 @@ export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', // attempts to transition the state and they were squashing each other. let path = GetBasePath(list.basePath) || GetBasePath(list.name); - qs.search(path, $stateParams[`${list.iterator}_search`]) + qs.search(path, $state.params[`${list.iterator}_search`]) .then(function(searchResponse) { $scope[`${list.iterator}_dataset`] = searchResponse.data; $scope[list.name] = $scope[`${list.iterator}_dataset`].results; diff --git a/awx/ui/client/src/templates/list/templates-list.route.js b/awx/ui/client/src/templates/list/templates-list.route.js index e615e52db1..6846620d17 100644 --- a/awx/ui/client/src/templates/list/templates-list.route.js +++ b/awx/ui/client/src/templates/list/templates-list.route.js @@ -4,11 +4,13 @@ * All Rights Reserved *************************************************/ + import { N_ } from '../../i18n'; + export default { name: 'templates', route: '/templates', ncyBreadcrumb: { - label: "TEMPLATES" + label: N_("TEMPLATES") }, data: { activityStream: true, diff --git a/awx/ui/client/src/widgets/Stream.js b/awx/ui/client/src/widgets/Stream.js index 5c2a6892ec..a3e033214e 100644 --- a/awx/ui/client/src/widgets/Stream.js +++ b/awx/ui/client/src/widgets/Stream.js @@ -92,8 +92,8 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti } ]) -.factory('BuildDescription', ['BuildAnchor', '$log', - function (BuildAnchor, $log) { +.factory('BuildDescription', ['BuildAnchor', '$log', 'i18n', + function (BuildAnchor, $log, i18n) { return function (activity) { var pastTense = function(operation){ @@ -212,7 +212,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti } catch(err){ $log.debug(err); - activity.description = 'Event summary not available'; + activity.description = i18n._('Event summary not available'); } }; } @@ -258,10 +258,10 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti .factory('Stream', ['$rootScope', '$location', '$state', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'generateList', 'FormatDate', 'BuildDescription', - 'ShowDetail', + 'ShowDetail', 'i18n', function ($rootScope, $location, $state, Rest, GetBasePath, ProcessErrors, Wait, StreamList, GenerateList, FormatDate, - BuildDescription, ShowDetail) { + BuildDescription, ShowDetail, i18n) { return function (params) { var list = _.cloneDeep(StreamList), @@ -297,7 +297,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti if ($state.params.target === 'credential') { list.fields.customSearchField = { - label: 'Credential', + label: i18n._('Credential'), searchType: 'text', searchOnly: 'true', sourceModel: 'credential', @@ -305,7 +305,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'host') { list.fields.customSearchField = { - label: 'Host', + label: i18n._('Host'), searchType: 'text', searchOnly: 'true', sourceModel: 'host', @@ -313,7 +313,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'inventory') { list.fields.customSearchField = { - label: 'Inventory', + label: i18n._('Inventory'), searchType: 'text', searchOnly: 'true', sourceModel: 'inventory', @@ -321,7 +321,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'inventory_script') { list.fields.customSearchField = { - label: 'Inventory Script', + label: i18n._('Inventory Script'), searchType: 'text', searchOnly: 'true', sourceModel: 'custom_inventory_script', @@ -329,7 +329,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'job_template') { list.fields.customSearchField = { - label: 'Job Template', + label: i18n._('Job Template'), searchType: 'text', searchOnly: 'true', sourceModel: 'job_template', @@ -337,7 +337,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'job') { list.fields.customSearchField = { - label: 'Job', + label: i18n._('Job'), searchType: 'text', searchOnly: 'true', sourceModel: 'job', @@ -345,7 +345,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'organization') { list.fields.customSearchField = { - label: 'Organization', + label: i18n._('Organization'), searchType: 'text', searchOnly: 'true', sourceModel: 'organization', @@ -353,7 +353,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'project') { list.fields.customSearchField = { - label: 'Project', + label: i18n._('Project'), searchType: 'text', searchOnly: 'true', sourceModel: 'project', @@ -361,7 +361,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'schedule') { list.fields.customSearchField = { - label: 'Schedule', + label: i18n._('Schedule'), searchType: 'text', searchOnly: 'true', sourceModel: 'schedule', @@ -369,7 +369,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'team') { list.fields.customSearchField = { - label: 'Team', + label: i18n._('Team'), searchType: 'text', searchOnly: 'true', sourceModel: 'team', @@ -377,7 +377,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }; } else if ($state.params.target === 'user') { list.fields.customSearchField = { - label: 'User', + label: i18n._('User'), searchType: 'text', searchOnly: 'true', sourceModel: 'user', diff --git a/awx/ui/client/src/workflow-results/workflow-results.partial.html b/awx/ui/client/src/workflow-results/workflow-results.partial.html index f63021037a..a1b6c40db1 100644 --- a/awx/ui/client/src/workflow-results/workflow-results.partial.html +++ b/awx/ui/client/src/workflow-results/workflow-results.partial.html @@ -26,7 +26,7 @@ data-placement="top" mode="all" ng-click="relaunchJob()" - aw-tool-tip="Relaunch using the same parameters" + aw-tool-tip="{{'Relaunch using the same parameters'|translate}}" data-original-title="" title=""> @@ -39,7 +39,7 @@ ng-click="deleteJob()" ng-show="workflow_status.status == 'running' || job_status.status=='pending' " - aw-tool-tip="Cancel" + aw-tool-tip="{{'Cancel'|translate}}" data-original-title="" title=""> @@ -51,7 +51,7 @@ ng-click="deleteJob()" ng-hide="job_status.status == 'running' || job_status.status == 'pending' " - aw-tool-tip="Delete" + aw-tool-tip="{{'Delete'|translate}}" data-original-title="" title=""> @@ -106,7 +106,7 @@
{{ workflow.summary_fields.created_by.username }} @@ -122,7 +122,7 @@ WorkflowResults-resultRowLabel--fullWidth"> Extra Variables diff --git a/awx/ui/po/ansible-tower-ui.pot b/awx/ui/po/ansible-tower-ui.pot index 1d0e6f72bf..99c21feda4 100644 --- a/awx/ui/po/ansible-tower-ui.pot +++ b/awx/ui/po/ansible-tower-ui.pot @@ -4,7 +4,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Project-Id-Version: \n" -#: client/src/notifications/notificationTemplates.form.js:372 +#: client/src/notifications/notificationTemplates.form.js:375 msgid "%s or %s" msgstr "" @@ -26,10 +26,30 @@ msgstr "" msgid "+ ADD" msgstr "" +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:32 +msgid "A schedule name is required." +msgstr "" + #: client/src/controllers/Users.js:185 msgid "A value is required" msgstr "" +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:160 +msgid "A value is required." +msgstr "" + +#: client/src/about/about.route.js:10 +msgid "ABOUT" +msgstr "" + +#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:16 +msgid "ACTION" +msgstr "" + +#: client/src/activity-stream/activitystream.route.js:27 +msgid "ACTIVITY STREAM" +msgstr "" + #: client/src/forms/Credentials.js:449 #: client/src/forms/Inventories.js:153 #: client/src/forms/JobTemplates.js:427 @@ -41,27 +61,40 @@ msgstr "" #: client/src/lists/Credentials.js:60 #: client/src/lists/Inventories.js:68 #: client/src/lists/Projects.js:77 +#: client/src/lists/Schedules.js:69 #: client/src/lists/Teams.js:50 #: client/src/lists/Templates.js:62 #: client/src/lists/Users.js:58 -#: client/src/notifications/notificationTemplates.list.js:53 +#: client/src/notifications/notificationTemplates.list.js:52 msgid "ADD" msgstr "" -#: client/src/notifications/notifications.list.js:68 +#: client/src/notifications/notifications.list.js:66 msgid "ADD NOTIFICATION TEMPLATE" msgstr "" -#: client/src/forms/Teams.js:157 +#: client/src/forms/Teams.js:156 #: client/src/forms/Users.js:212 msgid "ADD PERMISSIONS" msgstr "" +#: client/src/shared/smart-search/smart-search.partial.html:54 +msgid "ADDITIONAL INFORMATION:" +msgstr "" + +#: client/src/organizations/linkout/organizations-linkout.route.js:363 +msgid "ADMINS" +msgstr "" + +#: client/src/helpers/ActivityStream.js:19 +msgid "ALL ACTIVITY" +msgstr "" + #: client/src/forms/Credentials.js:199 msgid "API Key" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:248 +#: client/src/notifications/notificationTemplates.form.js:251 msgid "API Service/Integration Key" msgstr "" @@ -77,16 +110,20 @@ msgstr "" msgid "Access Key" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:226 +#: client/src/notifications/notificationTemplates.form.js:229 msgid "Account SID" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:184 +#: client/src/notifications/notificationTemplates.form.js:187 msgid "Account Token" msgstr "" +#: client/src/forms/ActivityDetail.js:38 +msgid "Action" +msgstr "" + #: client/src/dashboard/lists/job-templates/job-templates-list.partial.html:20 -#: client/src/shared/list-generator/list-generator.factory.js:542 +#: client/src/shared/list-generator/list-generator.factory.js:546 msgid "Actions" msgstr "" @@ -95,7 +132,13 @@ msgstr "" msgid "Activity" msgstr "" +#: client/src/forms/ActivityDetail.js:25 +msgid "Activity Detail" +msgstr "" + #: client/src/configuration/system-form/configuration-system.controller.js:81 +#: client/src/lists/Streams.js:16 +#: client/src/lists/Streams.js:17 msgid "Activity Stream" msgstr "" @@ -104,6 +147,7 @@ msgstr "" #: client/src/forms/Organizations.js:72 #: client/src/forms/Teams.js:82 #: client/src/forms/Workflows.js:124 +#: client/src/organizations/linkout/addUsers/addUsers.partial.html:8 msgid "Add" msgstr "" @@ -119,10 +163,14 @@ msgstr "" msgid "Add Inventories" msgstr "" -#: client/src/notifications/notifications.list.js:63 +#: client/src/notifications/notifications.list.js:61 msgid "Add Notification" msgstr "" +#: client/src/shared/stateDefinitions.factory.js:277 +msgid "Add Permissions" +msgstr "" + #: client/src/lists/Projects.js:15 msgid "Add Project" msgstr "" @@ -142,9 +190,15 @@ msgid "Add User" msgstr "" #: client/src/lists/Users.js:25 +#: client/src/shared/stateDefinitions.factory.js:342 +#: client/src/shared/stateDefinitions.factory.js:511 msgid "Add Users" msgstr "" +#: client/src/lists/Schedules.js:67 +msgid "Add a new schedule" +msgstr "" + #: client/src/forms/Credentials.js:447 #: client/src/forms/Inventories.js:106 #: client/src/forms/Inventories.js:151 @@ -167,9 +221,17 @@ msgstr "" #: client/src/dashboard/graphs/dashboard-graphs.partial.html:43 #: client/src/dashboard/graphs/dashboard-graphs.partial.html:65 #: client/src/dashboard/graphs/dashboard-graphs.partial.html:74 +#: client/src/job-detail/job-detail.partial.html:197 +#: client/src/job-detail/job-detail.partial.html:256 +#: client/src/job-detail/job-detail.partial.html:340 msgid "All" msgstr "" +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:18 +msgid "All Activity" +msgstr "" + +#: client/src/lists/AllJobs.js:16 #: client/src/portal-mode/portal-mode-jobs.partial.html:7 msgid "All Jobs" msgstr "" @@ -191,6 +253,22 @@ msgstr "" msgid "An SCM update does not appear to be running for project: %s. Click the %sRefresh%s button to view the latest status." msgstr "" +#: client/src/controllers/Credentials.js:102 +msgid "Are you sure you want to delete the credential below?" +msgstr "" + +#: client/src/helpers/Jobs.js:231 +msgid "Are you sure you want to delete the job below?" +msgstr "" + +#: client/src/notifications/notification-templates-list/list.controller.js:184 +msgid "Are you sure you want to delete the notification template below?" +msgstr "" + +#: client/src/organizations/list/organizations-list.controller.js:166 +msgid "Are you sure you want to delete the organization below?" +msgstr "" + #: client/src/controllers/Projects.js:202 msgid "Are you sure you want to delete the project below?" msgstr "" @@ -199,10 +277,15 @@ msgstr "" msgid "Are you sure you want to delete the user below?" msgstr "" +#: client/src/controllers/Credentials.js:576 #: client/src/controllers/Projects.js:687 msgid "Are you sure you want to remove the %s below from %s?" msgstr "" +#: client/src/forms/EventsViewer.js:57 +msgid "Arguments" +msgstr "" + #: client/src/forms/Credentials.js:233 #: client/src/forms/Credentials.js:272 #: client/src/forms/Credentials.js:312 @@ -214,6 +297,10 @@ msgstr "" msgid "Auditor" msgstr "" +#: client/src/configuration/configuration.partial.html:15 +msgid "Authentication" +msgstr "" + #: client/src/forms/Credentials.js:73 msgid "Authentication for network device access. This can include SSH keys, usernames, passwords, and authorize information. Network credentials are used when submitting jobs to run playbooks against network devices." msgstr "" @@ -246,7 +333,41 @@ msgstr "" msgid "Browse" msgstr "" -#: client/src/app.js:316 +#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:20 +msgid "CHANGES" +msgstr "" + +#: client/src/shared/smart-search/smart-search.partial.html:31 +msgid "CLEAR ALL" +msgstr "" + +#: client/src/inventories/manage/copy-move/copy-move.route.js:29 +#: client/src/inventories/manage/copy-move/copy-move.route.js:65 +msgid "COPY OR MOVE" +msgstr "" + +#: client/src/shared/stateDefinitions.factory.js:153 +msgid "CREATE %s" +msgstr "" + +#: client/src/inventories/main.js:110 +#: client/src/scheduler/main.js:176 +#: client/src/scheduler/main.js:253 +#: client/src/scheduler/main.js:90 +msgid "CREATE SCHEDULE" +msgstr "" + +#: client/src/management-jobs/scheduler/main.js:74 +msgid "CREATE SCHEDULED JOB" +msgstr "" + +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:80 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:82 +msgid "CREDENTIAL" +msgstr "" + +#: client/src/app.js:319 +#: client/src/helpers/ActivityStream.js:29 msgid "CREDENTIALS" msgstr "" @@ -276,12 +397,20 @@ msgstr "" msgid "Call to %s failed. POST status:" msgstr "" +#: client/src/management-jobs/card/card.controller.js:30 +msgid "Call to %s failed. Return status: %d" +msgstr "" + #: client/src/controllers/Projects.js:266 msgid "Call to get project failed. GET status:" msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:171 #: client/src/configuration/configuration.controller.js:449 +#: client/src/helpers/Jobs.js:161 #: client/src/shared/form-generator.js:1696 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:12 +#: client/src/workflow-results/workflow-results.partial.html:42 msgid "Cancel" msgstr "" @@ -293,14 +422,28 @@ msgstr "" msgid "Cancel the SCM update" msgstr "" +#: client/src/lists/AllJobs.js:108 +msgid "Cancel the job" +msgstr "" + #: client/src/controllers/Projects.js:82 +#: client/src/helpers/Projects.js:79 msgid "Canceled. Click for details" msgstr "" +#: client/src/shared/smart-search/smart-search.controller.js:38 +#: client/src/shared/smart-search/smart-search.controller.js:80 +msgid "Cannot search running job" +msgstr "" + #: client/src/forms/Projects.js:82 msgid "Change %s under \"Configure Tower\" to change this location." msgstr "" +#: client/src/forms/ActivityDetail.js:43 +msgid "Changes" +msgstr "" + #: client/src/shared/form-generator.js:1082 msgid "Choose a %s" msgstr "" @@ -329,7 +472,7 @@ msgstr "" msgid "Client ID" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:259 +#: client/src/notifications/notificationTemplates.form.js:262 msgid "Client Identifier" msgstr "" @@ -343,6 +486,7 @@ msgstr "" #: client/src/forms/JobTemplates.js:166 #: client/src/forms/JobTemplates.js:178 +#: client/src/job-detail/job-detail.partial.html:124 msgid "Cloud Credential" msgstr "" @@ -357,7 +501,7 @@ msgstr "" msgid "Collapse Output" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:295 +#: client/src/notifications/notificationTemplates.form.js:298 msgid "Color can be one of %s." msgstr "" @@ -369,6 +513,11 @@ msgstr "" msgid "Configure Notifications" msgstr "" +#: client/src/configuration/configuration.partial.html:10 +#: client/src/setup-menu/setup-menu.partial.html:53 +msgid "Configure Tower" +msgstr "" + #: client/src/forms/Users.js:82 msgid "Confirm Password" msgstr "" @@ -420,8 +569,8 @@ msgstr "" msgid "Create a new inventory" msgstr "" -#: client/src/notifications/notificationTemplates.list.js:51 -#: client/src/notifications/notifications.list.js:66 +#: client/src/notifications/notificationTemplates.list.js:50 +#: client/src/notifications/notifications.list.js:64 msgid "Create a new notification template" msgstr "" @@ -453,19 +602,29 @@ msgstr "" msgid "Create templates for sending notifications with Email, HipChat, Slack, and SMS." msgstr "" +#: client/src/forms/EventsViewer.js:32 +#: client/src/lists/JobEvents.js:44 +msgid "Created On" +msgstr "" + #: client/src/forms/JobTemplates.js:156 #: client/src/forms/WorkflowMaker.js:60 #: client/src/forms/WorkflowMaker.js:69 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:67 +#: client/src/widgets/Stream.js:300 msgid "Credential" msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:123 +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:57 +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:19 #: client/src/lists/Credentials.js:18 #: client/src/lists/Credentials.js:19 #: client/src/setup-menu/setup-menu.partial.html:22 msgid "Credentials" msgstr "" -#: client/src/controllers/Credentials.js:345 +#: client/src/controllers/Credentials.js:346 msgid "Credentials are only shared within an organization. Assign credentials to an organization to delegate credential permissions. The organization cannot be edited after credentials are assigned." msgstr "" @@ -474,25 +633,42 @@ msgstr "" msgid "Custom Script" msgstr "" -#: client/src/app.js:408 +#: client/src/app.js:410 msgid "DASHBOARD" msgstr "" +#: client/src/controllers/Credentials.js:104 +#: client/src/controllers/Credentials.js:578 #: client/src/controllers/Projects.js:689 #: client/src/controllers/Users.js:104 +#: client/src/notifications/notification-templates-list/list.controller.js:189 +#: client/src/organizations/list/organizations-list.controller.js:168 msgid "DELETE" msgstr "" +#: client/src/job-detail/job-detail.partial.html:176 +#: client/src/job-detail/job-detail.partial.html:179 +msgid "DETAILS" +msgstr "" + +#: client/src/controllers/Credentials.js:101 +#: client/src/controllers/Credentials.js:575 #: client/src/controllers/Projects.js:201 #: client/src/controllers/Projects.js:686 #: client/src/controllers/Users.js:101 +#: client/src/helpers/Jobs.js:165 #: client/src/inventory-scripts/inventory-scripts.list.js:74 #: client/src/lists/Credentials.js:91 #: client/src/lists/Inventories.js:92 +#: client/src/lists/Schedules.js:91 #: client/src/lists/Teams.js:77 #: client/src/lists/Templates.js:125 #: client/src/lists/Users.js:87 -#: client/src/notifications/notificationTemplates.list.js:90 +#: client/src/notifications/notification-templates-list/list.controller.js:186 +#: client/src/notifications/notificationTemplates.list.js:89 +#: client/src/organizations/list/organizations-list.controller.js:165 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:13 +#: client/src/workflow-results/workflow-results.partial.html:54 msgid "Delete" msgstr "" @@ -508,7 +684,7 @@ msgstr "" msgid "Delete inventory script" msgstr "" -#: client/src/notifications/notificationTemplates.list.js:92 +#: client/src/notifications/notificationTemplates.list.js:91 msgid "Delete notification" msgstr "" @@ -516,6 +692,10 @@ msgstr "" msgid "Delete on Update" msgstr "" +#: client/src/lists/Schedules.js:94 +msgid "Delete schedule" +msgstr "" + #: client/src/lists/Teams.js:81 msgid "Delete team" msgstr "" @@ -524,6 +704,7 @@ msgstr "" msgid "Delete template" msgstr "" +#: client/src/lists/AllJobs.js:115 #: client/src/lists/CompletedJobs.js:82 msgid "Delete the job" msgstr "" @@ -563,24 +744,24 @@ msgstr "" #: client/src/lists/PortalJobTemplates.js:29 #: client/src/lists/Teams.js:30 #: client/src/lists/Templates.js:36 -#: client/src/notifications/notificationTemplates.form.js:36 +#: client/src/notifications/notificationTemplates.form.js:39 msgid "Description" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:138 -#: client/src/notifications/notificationTemplates.form.js:143 -#: client/src/notifications/notificationTemplates.form.js:155 -#: client/src/notifications/notificationTemplates.form.js:160 -#: client/src/notifications/notificationTemplates.form.js:373 +#: client/src/notifications/notificationTemplates.form.js:141 +#: client/src/notifications/notificationTemplates.form.js:146 +#: client/src/notifications/notificationTemplates.form.js:158 +#: client/src/notifications/notificationTemplates.form.js:163 +#: client/src/notifications/notificationTemplates.form.js:376 msgid "Destination Channels" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:368 +#: client/src/notifications/notificationTemplates.form.js:371 msgid "Destination Channels or Users" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:209 -#: client/src/notifications/notificationTemplates.form.js:214 +#: client/src/notifications/notificationTemplates.form.js:212 +#: client/src/notifications/notificationTemplates.form.js:217 msgid "Destination SMS Number" msgstr "" @@ -596,7 +777,7 @@ msgstr "" msgid "Discard changes" msgstr "" -#: client/src/forms/Teams.js:146 +#: client/src/forms/Teams.js:145 msgid "Dissasociate permission from team" msgstr "" @@ -610,7 +791,11 @@ msgstr "" msgid "Domain Name" msgstr "" +#: client/src/job-detail/job-detail.partial.html:420 #: client/src/job-results/job-results.controller.js:7 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:114 +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:137 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:102 msgid "Download Output" msgstr "" @@ -618,33 +803,61 @@ 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/management-jobs/scheduler/main.js:88 +msgid "EDIT SCHEDULED JOB" +msgstr "" + +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:46 +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:66 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:59 +msgid "ELAPSED" +msgstr "" + +#: client/src/job-detail/job-detail.partial.html:391 +#: client/src/job-detail/job-detail.partial.html:394 +msgid "EVENT SUMMARY" +msgstr "" + +#: client/src/shared/smart-search/smart-search.partial.html:40 +msgid "EXAMPLES:" +msgstr "" + #: 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 "" -#: client/src/dashboard/hosts/dashboard-hosts.list.js:63 +#: client/src/dashboard/hosts/dashboard-hosts.list.js:62 #: client/src/inventory-scripts/inventory-scripts.list.js:57 #: client/src/lists/Credentials.js:72 #: client/src/lists/Inventories.js:78 +#: client/src/lists/Schedules.js:76 #: client/src/lists/Teams.js:60 #: client/src/lists/Templates.js:108 #: client/src/lists/Users.js:68 -#: client/src/notifications/notificationTemplates.list.js:64 -#: client/src/notifications/notificationTemplates.list.js:73 +#: client/src/notifications/notificationTemplates.list.js:63 +#: client/src/notifications/notificationTemplates.list.js:72 msgid "Edit" msgstr "" +#: client/src/configuration/configuration.route.js:30 +msgid "Edit Configuration" +msgstr "" + #: client/src/forms/JobTemplates.js:479 #: client/src/forms/Workflows.js:179 #: client/src/shared/form-generator.js:1712 msgid "Edit Survey" msgstr "" +#: client/src/setup-menu/setup-menu.partial.html:54 +msgid "Edit Tower's configuration." +msgstr "" + #: client/src/lists/Credentials.js:74 msgid "Edit credential" msgstr "" -#: client/src/dashboard/hosts/dashboard-hosts.list.js:66 +#: client/src/dashboard/hosts/dashboard-hosts.list.js:65 msgid "Edit host" msgstr "" @@ -656,10 +869,14 @@ msgstr "" msgid "Edit inventory script" msgstr "" -#: client/src/notifications/notificationTemplates.list.js:75 +#: client/src/notifications/notificationTemplates.list.js:74 msgid "Edit notification" msgstr "" +#: client/src/lists/Schedules.js:79 +msgid "Edit schedule" +msgstr "" + #: client/src/lists/Teams.js:64 msgid "Edit team" msgstr "" @@ -668,6 +885,10 @@ msgstr "" msgid "Edit template" msgstr "" +#: client/src/workflow-results/workflow-results.partial.html:109 +msgid "Edit the User" +msgstr "" + #: client/src/lists/Projects.js:104 msgid "Edit the project" msgstr "" @@ -684,6 +905,14 @@ msgstr "" msgid "Either you do not have access or the SCM update process completed. Click the %sRefresh%s button to view the latest status." msgstr "" +#: client/src/forms/EventsViewer.js:81 +#: client/src/forms/LogViewerStatus.js:50 +#: client/src/job-detail/job-detail.partial.html:210 +#: client/src/job-detail/job-detail.partial.html:268 +#: client/src/job-detail/job-detail.partial.html:86 +msgid "Elapsed" +msgstr "" + #: client/src/forms/Credentials.js:192 #: client/src/forms/Users.js:42 msgid "Email" @@ -706,6 +935,10 @@ msgstr "" msgid "Encrypted credentials are not supported." msgstr "" +#: client/src/forms/EventsViewer.js:77 +msgid "End" +msgstr "" + #: client/src/license/license.partial.html:108 msgid "End User License Agreement" msgstr "" @@ -749,10 +982,38 @@ msgstr "" #: client/src/controllers/Users.js:94 #: client/src/helpers/Credentials.js:418 #: client/src/helpers/Credentials.js:434 +#: client/src/job-submission/job-submission-factories/launchjob.factory.js:168 +#: client/src/job-submission/job-submission-factories/launchjob.factory.js:187 #: client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js:119 +#: client/src/management-jobs/card/card.controller.js:150 +#: client/src/management-jobs/card/card.controller.js:240 +#: client/src/management-jobs/card/card.controller.js:29 msgid "Error!" msgstr "" +#: client/src/forms/EventsViewer.js:21 +#: client/src/forms/EventsViewer.js:25 +#: client/src/forms/EventsViewer.js:29 +#: client/src/forms/EventsViewer.js:33 +#: client/src/forms/EventsViewer.js:37 +#: client/src/forms/EventsViewer.js:42 +#: client/src/forms/EventsViewer.js:46 +#: client/src/forms/EventsViewer.js:50 +#: client/src/forms/EventsViewer.js:54 +#: client/src/forms/EventsViewer.js:58 +#: client/src/lists/JobEvents.js:65 +#: client/src/lists/Streams.js:43 +msgid "Event" +msgstr "" + +#: client/src/widgets/Stream.js:215 +msgid "Event summary not available" +msgstr "" + +#: client/src/lists/JobEvents.js:31 +msgid "Events" +msgstr "" + #: client/src/controllers/Projects.js:421 #: client/src/controllers/Projects.js:704 msgid "Example URLs for GIT SCM include:" @@ -781,10 +1042,16 @@ msgstr "" msgid "Expires On" msgstr "" +#: client/src/job-detail/job-detail.partial.html:31 +msgid "Explanation" +msgstr "" + #: client/src/forms/JobTemplates.js:365 #: client/src/forms/JobTemplates.js:377 #: client/src/forms/Workflows.js:72 #: client/src/forms/Workflows.js:84 +#: client/src/job-detail/job-detail.partial.html:163 +#: client/src/partials/logviewer.html:8 msgid "Extra Variables" msgstr "" @@ -792,7 +1059,20 @@ msgstr "" msgid "FAILED" msgstr "" +#: client/src/shared/smart-search/smart-search.partial.html:48 +msgid "FIELDS:" +msgstr "" + +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:39 +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:59 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:52 +msgid "FINISHED" +msgstr "" + #: client/src/dashboard/graphs/dashboard-graphs.partial.html:80 +#: client/src/job-detail/job-detail.partial.html:198 +#: client/src/job-detail/job-detail.partial.html:257 +#: client/src/job-detail/job-detail.partial.html:341 msgid "Failed" msgstr "" @@ -816,6 +1096,10 @@ msgstr "" msgid "Failed to get third-party login types. Returned status:" msgstr "" +#: client/src/job-submission/job-submission-factories/launchjob.factory.js:188 +msgid "Failed to retrieve job template extra variables." +msgstr "" + #: client/src/controllers/Projects.js:598 msgid "Failed to retrieve project: %s. GET status:" msgstr "" @@ -841,35 +1125,61 @@ msgstr "" msgid "Failed to update project: %s. PUT status:" msgstr "" -#: client/src/notifications/notifications.list.js:49 +#: client/src/job-submission/job-submission-factories/launchjob.factory.js:169 +#: client/src/management-jobs/card/card.controller.js:151 +#: client/src/management-jobs/card/card.controller.js:241 +msgid "Failed updating job %s with variables. POST returned: %d" +msgstr "" + +#: client/src/helpers/Projects.js:73 +msgid "Failed. Click for details" +msgstr "" + +#: client/src/notifications/notifications.list.js:48 msgid "Failure" msgstr "" +#: client/src/lists/Schedules.js:49 +msgid "Final Run" +msgstr "" + +#: client/src/forms/LogViewerStatus.js:44 +#: client/src/job-detail/job-detail.partial.html:74 +#: client/src/lists/AllJobs.js:68 #: client/src/lists/CompletedJobs.js:56 #: client/src/lists/PortalJobs.js:37 msgid "Finished" msgstr "" +#: client/src/access/rbac-multiselect/permissionsUsers.list.js:27 #: client/src/forms/Users.js:28 #: client/src/lists/Users.js:41 msgid "First Name" msgstr "" +#: client/src/lists/Schedules.js:39 +msgid "First Run" +msgstr "" + +#: client/src/shared/smart-search/smart-search.partial.html:54 +msgid "For additional information on advanced search search syntax please see the Ansible Tower documentation." +msgstr "" + #: client/src/helpers/Credentials.js:143 #: client/src/helpers/Credentials.js:279 msgid "For example, %s" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:142 -#: client/src/notifications/notificationTemplates.form.js:159 -#: client/src/notifications/notificationTemplates.form.js:213 -#: client/src/notifications/notificationTemplates.form.js:334 -#: client/src/notifications/notificationTemplates.form.js:372 -#: client/src/notifications/notificationTemplates.form.js:98 +#: client/src/notifications/notificationTemplates.form.js:101 +#: client/src/notifications/notificationTemplates.form.js:145 +#: client/src/notifications/notificationTemplates.form.js:162 +#: client/src/notifications/notificationTemplates.form.js:216 +#: client/src/notifications/notificationTemplates.form.js:337 +#: client/src/notifications/notificationTemplates.form.js:375 msgid "For example:" msgstr "" -#: client/src/dashboard/hosts/dashboard-hosts.list.js:54 +#: client/src/dashboard/hosts/dashboard-hosts.list.js:53 msgid "For hosts that are part of an external inventory, this flag cannot be changed. It will be set by the inventory sync process." msgstr "" @@ -880,9 +1190,19 @@ msgstr "" #: client/src/forms/JobTemplates.js:201 #: client/src/forms/JobTemplates.js:214 +#: client/src/job-detail/job-detail.partial.html:138 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:87 msgid "Forks" msgstr "" +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:165 +msgid "Frequency Details" +msgstr "" + +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:89 +msgid "GROUP" +msgstr "" + #: client/src/configuration/auth-form/configuration-auth.controller.js:102 msgid "GitHub" msgstr "" @@ -899,7 +1219,7 @@ msgstr "" msgid "Google OAuth2" msgstr "" -#: client/src/forms/Teams.js:155 +#: client/src/forms/Teams.js:154 #: client/src/forms/Users.js:210 msgid "Grant Permission" msgstr "" @@ -908,12 +1228,24 @@ msgstr "" msgid "Group all of your content to manage permissions across departments in your company." msgstr "" -#: client/src/notifications/notificationTemplates.form.js:324 +#: client/src/dashboard/hosts/main.js:55 +#: client/src/helpers/ActivityStream.js:50 +msgid "HOSTS" +msgstr "" + +#: client/src/notifications/notificationTemplates.form.js:327 msgid "HTTP Headers" msgstr "" +#: client/src/bread-crumb/bread-crumb.directive.js:106 +msgid "Hide Activity Stream" +msgstr "" + #: client/src/forms/Credentials.js:140 -#: client/src/notifications/notificationTemplates.form.js:72 +#: client/src/forms/EventsViewer.js:20 +#: client/src/lists/JobEvents.js:73 +#: client/src/notifications/notificationTemplates.form.js:75 +#: client/src/widgets/Stream.js:308 msgid "Host" msgstr "" @@ -927,11 +1259,21 @@ msgstr "" msgid "Host Config Key" msgstr "" -#: client/src/dashboard/hosts/dashboard-hosts.list.js:55 +#: client/src/dashboard/hosts/dashboard-hosts.list.js:54 msgid "Host Enabled" msgstr "" +#: client/src/job-detail/job-detail.partial.html:269 +msgid "Host Status" +msgstr "" + +#: client/src/lists/JobEvents.js:37 +msgid "Host Summary" +msgstr "" + +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:20 #: client/src/dashboard/counts/dashboard-counts.directive.js:39 +#: client/src/job-detail/job-detail.partial.html:349 msgid "Hosts" msgstr "" @@ -951,16 +1293,32 @@ msgstr "" msgid "I agree to the End User License Agreement" msgstr "" +#: client/src/forms/EventsViewer.js:28 +msgid "ID" +msgstr "" + +#: client/src/activity-stream/streamDetailModal/streamDetailModal.partial.html:12 +msgid "INITIATED BY" +msgstr "" + +#: client/src/helpers/ActivityStream.js:26 +#: client/src/inventories/main.js:291 #: client/src/main-menu/main-menu.partial.html:104 #: client/src/main-menu/main-menu.partial.html:27 +#: client/src/organizations/linkout/organizations-linkout.route.js:178 msgid "INVENTORIES" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:357 +#: client/src/helpers/ActivityStream.js:44 +#: client/src/inventory-scripts/main.js:66 +msgid "INVENTORY SCRIPTS" +msgstr "" + +#: client/src/notifications/notificationTemplates.form.js:360 msgid "IRC Nick" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:346 +#: client/src/notifications/notificationTemplates.form.js:349 msgid "IRC Server Address" msgstr "" @@ -972,6 +1330,17 @@ msgstr "" msgid "IRC Server Port" msgstr "" +#: client/src/shared/paginate/paginate.partial.html:39 +msgid "" +"ITEMS \n" +" {{dataRange}}\n" +" of {{dataCount()}}" +msgstr "" + +#: client/src/login/authenticationServices/timer.factory.js:157 +msgid "Idle Session" +msgstr "" + #: client/src/forms/JobTemplates.js:293 msgid "If enabled, run this playbook as an administrator. This is the equivalent of passing the %s option to the %s command." msgstr "" @@ -988,10 +1357,15 @@ msgstr "" msgid "If you are ready to upgrade, please contact us by clicking the button below" msgstr "" -#: client/src/dashboard/hosts/dashboard-hosts.list.js:54 +#: client/src/dashboard/hosts/dashboard-hosts.list.js:53 msgid "Indicates if a host is available and should be included in running jobs." msgstr "" +#: client/src/forms/ActivityDetail.js:33 +#: client/src/lists/Streams.js:36 +msgid "Initiated by" +msgstr "" + #: client/src/forms/JobTemplates.js:58 msgid "Instead, %s will check playbook syntax, test environment setup and report problems." msgstr "" @@ -1009,6 +1383,9 @@ msgstr "" msgid "Invalid username and/or password. Please try again." msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:116 +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:51 +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:21 #: client/src/dashboard/counts/dashboard-counts.directive.js:50 #: client/src/lists/Inventories.js:16 #: client/src/lists/Inventories.js:17 @@ -1020,9 +1397,17 @@ msgstr "" #: client/src/forms/JobTemplates.js:87 #: client/src/forms/WorkflowMaker.js:79 #: client/src/forms/WorkflowMaker.js:89 +#: client/src/job-detail/job-detail.partial.html:98 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:58 +#: client/src/widgets/Stream.js:316 msgid "Inventory" msgstr "" +#: client/src/widgets/Stream.js:324 +msgid "Inventory Script" +msgstr "" + +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:22 #: client/src/inventory-scripts/inventory-scripts.list.js:12 #: client/src/setup-menu/setup-menu.partial.html:34 msgid "Inventory Scripts" @@ -1040,6 +1425,11 @@ msgstr "" msgid "Inventory Variables" msgstr "" +#: client/src/forms/EventsViewer.js:49 +#: client/src/job-detail/job-detail.partial.html:350 +msgid "Item" +msgstr "" + #: client/src/dashboard/graphs/dashboard-graphs.partial.html:4 msgid "JOB STATUS" msgstr "" @@ -1048,24 +1438,41 @@ msgstr "" msgid "JOB TEMPLATE" msgstr "" -#: client/src/app.js:428 +#: client/src/organizations/linkout/organizations-linkout.route.js:287 +msgid "JOB TEMPLATES" +msgstr "" + +#: client/src/app.js:430 #: client/src/dashboard/graphs/job-status/job-status-graph.directive.js:113 +#: client/src/helpers/ActivityStream.js:41 #: client/src/main-menu/main-menu.partial.html:122 #: client/src/main-menu/main-menu.partial.html:43 msgid "JOBS" msgstr "" +#: client/src/widgets/Stream.js:340 +msgid "Job" +msgstr "" + +#: client/src/lists/JobEvents.js:15 +msgid "Job Events" +msgstr "" + #: client/src/forms/JobTemplates.js:250 #: client/src/forms/JobTemplates.js:258 #: client/src/forms/WorkflowMaker.js:134 #: client/src/forms/WorkflowMaker.js:142 +#: client/src/job-detail/job-detail.partial.html:153 msgid "Job Tags" msgstr "" #: client/src/lists/Templates.js:65 +#: client/src/widgets/Stream.js:332 msgid "Job Template" msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:35 +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:97 #: client/src/lists/PortalJobTemplates.js:15 #: client/src/lists/PortalJobTemplates.js:16 msgid "Job Templates" @@ -1076,24 +1483,45 @@ msgstr "" #: client/src/forms/JobTemplates.js:62 #: client/src/forms/WorkflowMaker.js:110 #: client/src/forms/WorkflowMaker.js:99 +#: client/src/job-detail/job-detail.partial.html:69 msgid "Job Type" msgstr "" +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:23 +#: client/src/configuration/configuration.partial.html:16 #: client/src/lists/PortalJobs.js:15 #: client/src/lists/PortalJobs.js:19 #: client/src/partials/jobs.html:7 msgid "Jobs" msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:90 +#: client/src/shared/smart-search/smart-search.partial.html:14 +msgid "Key" +msgstr "" + +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:73 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:66 +msgid "LAUNCH TYPE" +msgstr "" + #: client/src/configuration/auth-form/configuration-auth.controller.js:106 msgid "LDAP" msgstr "" +#: client/src/license/license.route.js:18 +msgid "LICENSE" +msgstr "" + +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:45 +msgid "LICENSE ERROR" +msgstr "" + #: client/src/main-menu/main-menu.partial.html:83 msgid "LOG OUT" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:270 +#: client/src/notifications/notificationTemplates.form.js:273 msgid "Label to be shown with notification" msgstr "" @@ -1101,10 +1529,12 @@ msgstr "" #: client/src/forms/JobTemplates.js:358 #: client/src/forms/Workflows.js:60 #: client/src/forms/Workflows.js:65 +#: client/src/lists/AllJobs.js:76 #: client/src/lists/Templates.js:47 msgid "Labels" msgstr "" +#: client/src/access/rbac-multiselect/permissionsUsers.list.js:31 #: client/src/forms/Users.js:35 #: client/src/lists/Users.js:45 msgid "Last Name" @@ -1124,11 +1554,25 @@ msgstr "" msgid "Launch Management Job" msgstr "" +#: client/src/forms/LogViewerStatus.js:55 +msgid "Launch Type" +msgstr "" + +#: client/src/job-detail/job-detail.partial.html:79 +#: client/src/job-detail/job-detail.partial.html:91 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:76 +msgid "Launched By" +msgstr "" + #: client/src/license/license.controller.js:42 #: client/src/license/license.partial.html:8 msgid "License" msgstr "" +#: client/src/forms/LogViewerStatus.js:33 +msgid "License Error" +msgstr "" + #: client/src/license/license.partial.html:102 msgid "License File" msgstr "" @@ -1149,6 +1593,8 @@ msgstr "" #: client/src/forms/JobTemplates.js:227 #: client/src/forms/WorkflowMaker.js:120 #: client/src/forms/WorkflowMaker.js:127 +#: client/src/job-detail/job-detail.partial.html:143 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:92 msgid "Limit" msgstr "" @@ -1164,10 +1610,16 @@ msgstr "" msgid "Live events: error connecting to the Tower server." msgstr "" +#: client/src/job-detail/job-detail.partial.html:316 +#: client/src/job-detail/job-detail.partial.html:371 #: client/src/shared/form-generator.js:1977 msgid "Loading..." msgstr "" +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:128 +msgid "Local Time Zone" +msgstr "" + #: client/src/main-menu/main-menu.partial.html:188 msgid "Log Out" msgstr "" @@ -1180,11 +1632,16 @@ msgstr "" msgid "MANAGEMENT JOBS" msgstr "" +#: client/src/portal-mode/portal-mode.route.js:12 +msgid "MY VIEW" +msgstr "" + #: client/src/forms/Credentials.js:68 msgid "Machine" msgstr "" #: client/src/forms/JobTemplates.js:138 +#: client/src/job-detail/job-detail.partial.html:117 msgid "Machine Credential" msgstr "" @@ -1215,10 +1672,27 @@ msgstr "" msgid "Maximum per-user sessions reached. Please sign in." msgstr "" +#: client/src/forms/EventsViewer.js:65 +#: client/src/job-detail/job-detail.partial.html:351 +msgid "Message" +msgstr "" + #: client/src/configuration/system-form/configuration-system.controller.js:80 msgid "Misc. System" msgstr "" +#: client/src/helpers/Projects.js:76 +msgid "Missing. Click for details" +msgstr "" + +#: client/src/forms/EventsViewer.js:53 +msgid "Module" +msgstr "" + +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:53 +msgid "Module Args" +msgstr "" + #: client/src/portal-mode/portal-mode-jobs.partial.html:4 msgid "My Jobs" msgstr "" @@ -1227,18 +1701,38 @@ msgstr "" msgid "My View" msgstr "" +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:19 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:19 +msgid "NAME" +msgstr "" + #: client/src/dashboard/hosts/dashboard-hosts.list.js:18 msgid "NO HOSTS FOUND" msgstr "" +#: client/src/login/loginModal/loginModal.partial.html:89 +msgid "NOTICE" +msgstr "" + +#: client/src/notifications/notificationTemplates.form.js:21 +msgid "NOTIFICATION TEMPLATE" +msgstr "" + +#: client/src/management-jobs/notifications/notification.route.js:46 +#: client/src/notifications/main.js:43 +#: client/src/notifications/main.js:88 +msgid "NOTIFICATIONS" +msgstr "" + #: client/src/dashboard/lists/job-templates/job-templates-list.partial.html:14 #: client/src/dashboard/lists/jobs/jobs-list.partial.html:13 #: client/src/forms/Credentials.js:34 #: client/src/forms/Inventories.js:29 #: client/src/forms/JobTemplates.js:35 +#: client/src/forms/LogViewerStatus.js:23 #: client/src/forms/Organizations.js:26 #: client/src/forms/Projects.js:31 -#: client/src/forms/Teams.js:124 +#: client/src/forms/Teams.js:123 #: client/src/forms/Teams.js:27 #: client/src/forms/Users.js:140 #: client/src/forms/Users.js:165 @@ -1246,6 +1740,7 @@ msgstr "" #: 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/AllJobs.js:45 #: client/src/lists/CompletedJobs.js:43 #: client/src/lists/Credentials.js:29 #: client/src/lists/Inventories.js:46 @@ -1253,11 +1748,14 @@ msgstr "" #: client/src/lists/PortalJobs.js:32 #: client/src/lists/Projects.js:38 #: client/src/lists/ScheduledJobs.js:32 +#: client/src/lists/Schedules.js:34 #: client/src/lists/Teams.js:25 #: client/src/lists/Templates.js:26 -#: client/src/notifications/notificationTemplates.form.js:29 -#: client/src/notifications/notificationTemplates.list.js:33 +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:21 +#: client/src/notifications/notificationTemplates.form.js:32 +#: client/src/notifications/notificationTemplates.list.js:32 #: client/src/notifications/notifications.list.js:26 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:19 msgid "Name" msgstr "" @@ -1267,6 +1765,7 @@ msgstr "" #: client/src/forms/JobTemplates.js:184 #: client/src/forms/JobTemplates.js:195 +#: client/src/job-detail/job-detail.partial.html:131 msgid "Network Credential" msgstr "" @@ -1315,6 +1814,7 @@ msgid "New user successfully created!" msgstr "" #: client/src/lists/ScheduledJobs.js:51 +#: client/src/lists/Schedules.js:44 msgid "Next Run" msgstr "" @@ -1326,10 +1826,22 @@ msgstr "" msgid "No SCM Configuration" msgstr "" +#: client/src/helpers/Projects.js:58 +msgid "No SCM updates have run for this project" +msgstr "" + +#: client/src/access/rbac-multiselect/permissionsTeams.list.js:18 +msgid "No Teams exist" +msgstr "" + #: client/src/controllers/Projects.js:152 msgid "No Updates Available" msgstr "" +#: client/src/access/rbac-multiselect/permissionsUsers.list.js:24 +msgid "No Users exist" +msgstr "" + #: client/src/lists/CompletedJobs.js:22 msgid "No completed jobs" msgstr "" @@ -1338,6 +1850,10 @@ msgstr "" msgid "No file selected." msgstr "" +#: client/src/dashboard/lists/job-templates/job-templates-list.partial.html:56 +msgid "No job templates were recently used." +msgstr "" + #: client/src/lists/AllJobs.js:20 msgid "No jobs have yet run." msgstr "" @@ -1346,11 +1862,31 @@ msgstr "" msgid "No jobs were recently run." msgstr "" -#: client/src/forms/Teams.js:121 +#: client/src/job-detail/job-detail.partial.html:374 +msgid "No matching host events" +msgstr "" + +#: client/src/job-detail/job-detail.partial.html:307 +msgid "No matching hosts." +msgstr "" + +#: client/src/job-detail/job-detail.partial.html:319 +msgid "No matching tasks" +msgstr "" + +#: client/src/forms/Teams.js:120 #: client/src/forms/Users.js:187 msgid "No permissions have been granted" msgstr "" +#: client/src/notifications/notification-templates-list/list.controller.js:88 +msgid "No recent notifications." +msgstr "" + +#: client/src/shared/form-generator.js:1874 +msgid "No records matched your search." +msgstr "" + #: client/src/lists/ScheduledJobs.js:18 msgid "No schedules exist" msgstr "" @@ -1363,24 +1899,29 @@ msgstr "" msgid "Not configured for SCM" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:293 +#: client/src/notifications/notificationTemplates.form.js:296 msgid "Notification Color" msgstr "" +#: client/src/notifications/notification-templates-list/list.controller.js:115 +msgid "Notification Failed." +msgstr "" + #: client/src/notifications/notificationTemplates.list.js:14 msgid "Notification Templates" msgstr "" +#: client/src/management-jobs/notifications/notification.route.js:21 #: client/src/notifications/notifications.list.js:17 #: client/src/setup-menu/setup-menu.partial.html:41 msgid "Notifications" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:306 +#: client/src/notifications/notificationTemplates.form.js:309 msgid "Notify Channel" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:198 +#: client/src/notifications/notificationTemplates.form.js:201 msgid "Number associated with the \"Messaging Service\" in Twilio." msgstr "" @@ -1392,10 +1933,20 @@ msgstr "" msgid "ON" msgstr "" +#: client/src/helpers/ActivityStream.js:38 #: client/src/organizations/list/organizations-list.partial.html:6 +#: client/src/organizations/main.js:52 msgid "ORGANIZATIONS" msgstr "" +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:112 +msgid "OVERWRITE" +msgstr "" + +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:119 +msgid "OVERWRITE VARS" +msgstr "" + #: client/src/forms/WorkflowMaker.js:45 msgid "On Failure" msgstr "" @@ -1414,6 +1965,8 @@ msgid "Optional labels that describe this job template, such as 'dev' or 'test'. msgstr "" #: client/src/forms/JobTemplates.js:286 +#: client/src/notifications/notificationTemplates.form.js:395 +#: client/src/partials/logviewer.html:7 msgid "Options" msgstr "" @@ -1430,10 +1983,12 @@ msgstr "" #: client/src/inventory-scripts/inventory-scripts.list.js:30 #: client/src/lists/Inventories.js:52 #: client/src/lists/Teams.js:35 -#: client/src/notifications/notificationTemplates.form.js:41 +#: client/src/notifications/notificationTemplates.form.js:44 +#: client/src/widgets/Stream.js:348 msgid "Organization" msgstr "" +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:24 #: client/src/forms/Users.js:130 #: client/src/setup-menu/setup-menu.partial.html:4 msgid "Organizations" @@ -1461,12 +2016,26 @@ msgstr "" msgid "PORTAL MODE" msgstr "" +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:73 +msgid "PROJECT" +msgstr "" + +#: client/src/app.js:295 +#: client/src/helpers/ActivityStream.js:23 #: client/src/main-menu/main-menu.partial.html:19 #: client/src/main-menu/main-menu.partial.html:95 +#: client/src/organizations/linkout/organizations-linkout.route.js:229 msgid "PROJECTS" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:237 +#: client/src/shared/paginate/paginate.partial.html:33 +msgid "" +"Page\n" +" {{current()}} of\n" +" {{last()}}" +msgstr "" + +#: client/src/notifications/notificationTemplates.form.js:240 msgid "Pagerduty subdomain" msgstr "" @@ -1535,22 +2104,29 @@ msgstr "" #: client/src/controllers/Projects.js:324 #: client/src/controllers/Users.js:141 +#: client/src/templates/job_templates/add-job-template/job-template-add.controller.js:26 msgid "Permission Error" msgstr "" #: client/src/forms/Credentials.js:439 #: client/src/forms/Inventories.js:142 +#: client/src/forms/Inventories.js:95 #: client/src/forms/JobTemplates.js:416 #: client/src/forms/Organizations.js:64 #: client/src/forms/Projects.js:227 -#: client/src/forms/Teams.js:117 +#: client/src/forms/Teams.js:116 #: client/src/forms/Users.js:183 #: client/src/forms/Workflows.js:116 msgid "Permissions" msgstr "" +#: client/src/forms/EventsViewer.js:40 +msgid "Play" +msgstr "" + #: client/src/forms/JobTemplates.js:121 #: client/src/forms/JobTemplates.js:132 +#: client/src/job-detail/job-detail.partial.html:112 msgid "Playbook" msgstr "" @@ -1562,10 +2138,22 @@ msgstr "" msgid "Playbook Run" msgstr "" +#: client/src/job-detail/job-detail.partial.html:208 +msgid "Plays" +msgstr "" + #: client/src/forms/Users.js:124 msgid "Please add user to an Organization." msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:89 +msgid "Please assign roles to the selected resources" +msgstr "" + +#: client/src/access/add-rbac-resource/rbac-resource.partial.html:62 +msgid "Please assign roles to the selected users/teams" +msgstr "" + #: client/src/license/license.partial.html:84 msgid "Please click the button below to visit Ansible's website to get a Tower license key." msgstr "" @@ -1618,12 +2206,13 @@ msgstr "" msgid "Please save before adding users" msgstr "" +#: client/src/controllers/Credentials.js:158 #: client/src/forms/Inventories.js:138 #: client/src/forms/Inventories.js:91 #: client/src/forms/JobTemplates.js:409 #: client/src/forms/Organizations.js:57 #: client/src/forms/Projects.js:219 -#: client/src/forms/Teams.js:113 +#: client/src/forms/Teams.js:112 #: client/src/forms/Workflows.js:109 msgid "Please save before assigning permissions" msgstr "" @@ -1641,6 +2230,14 @@ msgstr "" msgid "Please save before defining the workflow graph" msgstr "" +#: client/src/access/add-rbac-resource/rbac-resource.partial.html:26 +msgid "Please select Users / Teams from the lists below." +msgstr "" + +#: client/src/access/add-rbac-resource/rbac-resource.partial.html:29 +msgid "Please select Users from the list below." +msgstr "" + #: client/src/forms/WorkflowMaker.js:65 msgid "Please select a Credential." msgstr "" @@ -1657,6 +2254,10 @@ msgstr "" msgid "Please select a number." msgstr "" +#: client/src/job-detail/job-detail.partial.html:245 +msgid "Please select a task below to view its associated hosts" +msgstr "" + #: client/src/shared/form-generator.js:1109 #: client/src/shared/form-generator.js:1178 #: client/src/shared/form-generator.js:1297 @@ -1676,6 +2277,10 @@ msgstr "" msgid "Please select at least one value." msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:29 +msgid "Please select resources from the lists below." +msgstr "" + #: client/src/notifications/shared/type-change.service.js:27 msgid "Port" msgstr "" @@ -1709,6 +2314,8 @@ msgstr "" #: client/src/forms/JobTemplates.js:98 #: client/src/helpers/Credentials.js:104 #: client/src/helpers/Credentials.js:240 +#: client/src/job-detail/job-detail.partial.html:105 +#: client/src/widgets/Stream.js:356 msgid "Project" msgstr "" @@ -1738,6 +2345,9 @@ msgstr "" msgid "Project lookup failed. GET returned:" msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:109 +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:46 +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:25 #: client/src/dashboard/counts/dashboard-counts.directive.js:61 #: client/src/lists/Projects.js:16 #: client/src/lists/Projects.js:17 @@ -1771,6 +2381,10 @@ msgstr "" msgid "Provisioning Callback URL" msgstr "" +#: client/src/helpers/Projects.js:63 +msgid "Queued. Click for details" +msgstr "" + #: client/src/configuration/auth-form/configuration-auth.controller.js:107 msgid "RADIUS" msgstr "" @@ -1788,37 +2402,73 @@ msgstr "" msgid "RECENTLY USED JOB TEMPLATES" msgstr "" +#: client/src/lists/JobEvents.js:89 #: client/src/lists/Projects.js:70 +#: client/src/lists/Schedules.js:62 +#: client/src/lists/Streams.js:57 #: client/src/partials/jobs.html:15 #: client/src/portal-mode/portal-mode-jobs.partial.html:12 msgid "REFRESH" msgstr "" +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:105 +msgid "REGIONS" +msgstr "" + +#: client/src/shared/smart-search/smart-search.partial.html:51 +msgid "RELATED FIELDS:" +msgstr "" + #: client/src/forms/JobTemplates.js:100 msgid "RESET" msgstr "" +#: client/src/job-detail/job-detail.partial.html:11 +#: client/src/job-detail/job-detail.partial.html:14 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:7 +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:7 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:7 +msgid "RESULTS" +msgstr "" + #: client/src/helpers/Credentials.js:235 #: client/src/helpers/Credentials.js:99 msgid "RSA Private Key" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:94 -#: client/src/notifications/notificationTemplates.form.js:99 +#: client/src/inventories/manage/adhoc/adhoc.route.js:26 +msgid "RUN COMMAND" +msgstr "" + +#: client/src/workflow-results/workflow-results.partial.html:125 +msgid "Read only view of extra variables added to the workflow." +msgstr "" + +#: client/src/notifications/notificationTemplates.list.js:26 +msgid "Recent Notifications" +msgstr "" + +#: client/src/notifications/notificationTemplates.form.js:102 +#: client/src/notifications/notificationTemplates.form.js:97 msgid "Recipient List" msgstr "" #: client/src/bread-crumb/bread-crumb.partial.html:6 #: client/src/lists/Projects.js:66 +#: client/src/lists/Schedules.js:58 +#: client/src/lists/Streams.js:54 msgid "Refresh the page" msgstr "" +#: client/src/lists/AllJobs.js:101 #: client/src/lists/CompletedJobs.js:75 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:11 +#: client/src/workflow-results/workflow-results.partial.html:29 msgid "Relaunch using the same parameters" msgstr "" #: client/src/access/add-rbac-user-team/rbac-selected-list.directive.js:37 -#: client/src/forms/Teams.js:142 +#: client/src/forms/Teams.js:141 #: client/src/forms/Users.js:218 msgid "Remove" msgstr "" @@ -1827,10 +2477,33 @@ msgstr "" msgid "Remove any local modifications prior to performing an update." msgstr "" +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:143 +msgid "Repeat frequency" +msgstr "" + #: client/src/license/license.partial.html:89 msgid "Request License" msgstr "" +#: client/src/shared/form-generator.js:681 +msgid "Reset" +msgstr "" + +#: client/src/forms/EventsViewer.js:62 +#: client/src/forms/EventsViewer.js:66 +#: client/src/forms/EventsViewer.js:69 +#: client/src/forms/EventsViewer.js:70 +msgid "Results" +msgstr "" + +#: client/src/job-detail/job-detail.partial.html:52 +msgid "Results Traceback" +msgstr "" + +#: client/src/forms/EventsViewer.js:61 +msgid "Return Code" +msgstr "" + #: client/src/configuration/auth-form/sub-forms/auth-azure.form.js:46 #: client/src/configuration/auth-form/sub-forms/auth-github-org.form.js:50 #: client/src/configuration/auth-form/sub-forms/auth-github-team.form.js:50 @@ -1856,20 +2529,39 @@ msgid "Revision #" msgstr "" #: client/src/forms/Credentials.js:461 +#: client/src/forms/EventsViewer.js:36 #: client/src/forms/Inventories.js:120 #: client/src/forms/Inventories.js:166 #: client/src/forms/Organizations.js:88 #: client/src/forms/Projects.js:249 -#: client/src/forms/Teams.js:135 +#: client/src/forms/Teams.js:134 #: client/src/forms/Teams.js:98 #: client/src/forms/Users.js:201 +#: client/src/forms/Workflows.js:140 msgid "Role" msgstr "" +#: client/src/helpers/Projects.js:67 +msgid "Running! Click for details" +msgstr "" + #: client/src/configuration/auth-form/configuration-auth.controller.js:108 msgid "SAML" msgstr "" +#: client/src/scheduler/main.js:293 +msgid "SCHEDULED" +msgstr "" + +#: client/src/helpers/ActivityStream.js:47 +#: client/src/inventories/main.js:59 +#: client/src/management-jobs/scheduler/main.js:26 +#: client/src/scheduler/main.js:122 +#: client/src/scheduler/main.js:205 +#: client/src/scheduler/main.js:36 +msgid "SCHEDULES" +msgstr "" + #: client/src/controllers/Projects.js:697 msgid "SCM Branch" msgstr "" @@ -1914,6 +2606,7 @@ msgid "SCM update currently running" msgstr "" #: client/src/main-menu/main-menu.partial.html:59 +#: client/src/setup-menu/setup.route.js:8 msgid "SETTINGS" msgstr "" @@ -1925,10 +2618,14 @@ msgstr "" msgid "SIGN IN WITH" msgstr "" -#: client/src/app.js:497 +#: client/src/app.js:499 msgid "SOCKETS" msgstr "" +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:98 +msgid "SOURCE" +msgstr "" + #: client/src/helpers/Credentials.js:169 #: client/src/helpers/Credentials.js:305 msgid "SSH Key" @@ -1938,10 +2635,29 @@ msgstr "" msgid "SSH key description" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:385 +#: client/src/notifications/notificationTemplates.form.js:388 msgid "SSL Connection" msgstr "" +#: client/src/job-detail/job-detail.partial.html:414 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:108 +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:131 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:96 +msgid "STANDARD OUT" +msgstr "" + +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:32 +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:52 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:45 +msgid "STARTED" +msgstr "" + +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:24 +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:37 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:37 +msgid "STATUS" +msgstr "" + #: client/src/forms/Credentials.js:120 #: client/src/forms/Credentials.js:128 msgid "STS Token" @@ -1951,11 +2667,16 @@ msgstr "" msgid "SUCCESSFUL" msgstr "" +#: client/src/system-tracking/system-tracking.route.js:18 +msgid "SYSTEM TRACKING" +msgstr "" + #: client/src/helpers/Credentials.js:150 #: client/src/helpers/Credentials.js:286 msgid "Satellite 6 URL" msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:176 #: client/src/shared/form-generator.js:1688 msgid "Save" msgstr "" @@ -1972,6 +2693,7 @@ msgid "Save successful!" msgstr "" #: client/src/lists/Templates.js:92 +#: client/src/widgets/Stream.js:364 msgid "Schedule" msgstr "" @@ -1991,7 +2713,13 @@ msgstr "" msgid "Scheduled Jobs" msgstr "" +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:26 +#: client/src/inventories/main.js:93 +#: client/src/management-jobs/scheduler/main.js:32 #: client/src/partials/jobs.html:10 +#: client/src/scheduler/main.js:153 +#: client/src/scheduler/main.js:236 +#: client/src/scheduler/main.js:67 msgid "Schedules" msgstr "" @@ -1999,6 +2727,11 @@ msgstr "" msgid "Script must begin with a hashbang sequence: i.e.... %s" msgstr "" +#: client/src/shared/smart-search/smart-search.controller.js:38 +#: client/src/shared/smart-search/smart-search.controller.js:83 +msgid "Search" +msgstr "" + #: client/src/forms/Credentials.js:105 msgid "Secret Key" msgstr "" @@ -2028,6 +2761,10 @@ msgstr "" msgid "Select group types" msgstr "" +#: client/src/access/rbac-multiselect/rbac-multiselect-role.directive.js:25 +msgid "Select roles" +msgstr "" + #: client/src/forms/JobTemplates.js:154 #: client/src/forms/WorkflowMaker.js:67 msgid "Select the credential you want the job to use when accessing the remote hosts. Choose the credential containing the username and SSH key or password that Ansible will need to log into the remote hosts." @@ -2054,7 +2791,7 @@ msgstr "" msgid "Selecting an optional cloud credential in the job template will pass along the access credentials to the running playbook, allowing provisioning into the cloud without manually passing parameters to the included modules." msgstr "" -#: client/src/notifications/notificationTemplates.form.js:83 +#: client/src/notifications/notificationTemplates.form.js:86 msgid "Sender Email" msgstr "" @@ -2103,6 +2840,7 @@ msgstr "" #: client/src/forms/JobTemplates.js:276 #: client/src/forms/WorkflowMaker.js:149 #: client/src/forms/WorkflowMaker.js:157 +#: client/src/job-detail/job-detail.partial.html:158 msgid "Skip Tags" msgstr "" @@ -2119,11 +2857,15 @@ msgstr "" msgid "Source Details" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:196 +#: client/src/notifications/notificationTemplates.form.js:199 msgid "Source Phone Number" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:333 +#: client/src/partials/logviewer.html:9 +msgid "Source Vars" +msgstr "" + +#: client/src/notifications/notificationTemplates.form.js:336 msgid "Specify HTTP Headers in JSON format" msgstr "" @@ -2135,6 +2877,22 @@ msgstr "" msgid "Split up your organization to associate content and control permissions for groups." msgstr "" +#: client/src/partials/logviewer.html:5 +msgid "Standard Out" +msgstr "" + +#: client/src/forms/EventsViewer.js:73 +msgid "Start" +msgstr "" + +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:40 +msgid "Start Date" +msgstr "" + +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:54 +msgid "Start Time" +msgstr "" + #: client/src/lists/PortalJobTemplates.js:42 #: client/src/lists/Templates.js:87 msgid "Start a job using this template" @@ -2145,14 +2903,35 @@ msgstr "" msgid "Start an SCM update" msgstr "" -#: client/src/dashboard/hosts/dashboard-hosts.list.js:49 +#: client/src/forms/LogViewerStatus.js:38 +#: client/src/job-detail/job-detail.partial.html:209 +#: client/src/job-detail/job-detail.partial.html:267 +#: client/src/job-detail/job-detail.partial.html:64 +msgid "Started" +msgstr "" + +#: client/src/dashboard/hosts/dashboard-hosts.list.js:48 +#: client/src/forms/EventsViewer.js:24 +#: client/src/forms/LogViewerStatus.js:28 +#: client/src/job-detail/job-detail.partial.html:26 +#: client/src/lists/JobEvents.js:51 +#: client/src/notifications/notification-templates-list/list.controller.js:73 +#: client/src/partials/logviewer.html:4 msgid "Status" msgstr "" +#: client/src/configuration/auth-form/configuration-auth.partial.html:3 +msgid "Sub Category" +msgstr "" + #: client/src/license/license.partial.html:121 msgid "Submit" msgstr "" +#: client/src/helpers/Jobs.js:230 +msgid "Submit the request to cancel?" +msgstr "" + #: client/src/license/license.partial.html:27 msgid "Subscription" msgstr "" @@ -2170,10 +2949,18 @@ msgstr "" msgid "Success" msgstr "" +#: client/src/helpers/Projects.js:70 +msgid "Success! Click for details" +msgstr "" + #: client/src/dashboard/graphs/dashboard-graphs.partial.html:77 msgid "Successful" msgstr "" +#: client/src/configuration/configuration.partial.html:17 +msgid "System" +msgstr "" + #: client/src/controllers/Users.js:18 msgid "System Administrator" msgstr "" @@ -2182,12 +2969,16 @@ msgstr "" msgid "System Auditor" msgstr "" -#: client/src/app.js:340 +#: client/src/app.js:343 +#: client/src/helpers/ActivityStream.js:35 +#: client/src/organizations/linkout/organizations-linkout.route.js:132 msgid "TEAMS" msgstr "" +#: client/src/helpers/ActivityStream.js:53 #: client/src/main-menu/main-menu.partial.html:113 #: client/src/main-menu/main-menu.partial.html:35 +#: client/src/templates/list/templates-list.route.js:13 msgid "TEMPLATES" msgstr "" @@ -2200,29 +2991,47 @@ msgstr "" msgid "Tags are useful when you have a large playbook, and you want to run a specific part of a play or task." msgstr "" -#: client/src/notifications/notificationTemplates.form.js:313 +#: client/src/notifications/notificationTemplates.form.js:316 msgid "Target URL" msgstr "" -#: client/src/forms/Credentials.js:468 +#: client/src/forms/EventsViewer.js:45 +msgid "Task" +msgstr "" + +#: client/src/job-detail/job-detail.partial.html:266 +msgid "Tasks" +msgstr "" + +#: client/src/widgets/Stream.js:372 +msgid "Team" +msgstr "" + +#: client/src/forms/Credentials.js:467 #: client/src/forms/Inventories.js:126 #: client/src/forms/Inventories.js:173 -#: client/src/forms/Organizations.js:95 +#: client/src/forms/Organizations.js:94 #: client/src/forms/Projects.js:255 +#: client/src/forms/Workflows.js:146 msgid "Team Roles" msgstr "" +#: client/src/access/add-rbac-resource/rbac-resource.partial.html:40 +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:27 #: client/src/forms/Users.js:156 #: client/src/lists/Teams.js:16 #: client/src/lists/Teams.js:17 #: client/src/setup-menu/setup-menu.partial.html:16 +#: client/src/shared/stateDefinitions.factory.js:342 msgid "Teams" msgstr "" +#: client/src/job-detail/job-detail.partial.html:57 #: client/src/lists/Templates.js:16 msgid "Template" msgstr "" +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:28 #: client/src/lists/Templates.js:17 #: client/src/lists/Templates.js:18 msgid "Templates" @@ -2232,7 +3041,7 @@ msgstr "" msgid "Tenant ID" msgstr "" -#: client/src/notifications/notificationTemplates.list.js:66 +#: client/src/notifications/notificationTemplates.list.js:65 msgid "Test notification" msgstr "" @@ -2249,6 +3058,10 @@ msgstr "" msgid "The SCM update process is running." msgstr "" +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:70 +msgid "The credential used to run this command." +msgstr "" + #: client/src/forms/Credentials.js:191 msgid "The email address assigned to the Google Compute Engine %sservice account." msgstr "" @@ -2262,6 +3075,10 @@ msgstr "" msgid "The host value" msgstr "" +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:61 +msgid "The inventory this command ran on." +msgstr "" + #: client/src/forms/JobTemplates.js:210 msgid "The number of parallel or simultaneous processes to use while executing the playbook. 0 signifies the default value from the %sansible configuration file%s." msgstr "" @@ -2278,6 +3095,18 @@ msgstr "" msgid "The selected project is not configured for SCM. To configure for SCM, edit the project and provide SCM settings, and then run an update." msgstr "" +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:119 +msgid "The time must be in HH24:MM:SS format." +msgstr "" + +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:79 +msgid "The user who ran this command." +msgstr "" + +#: client/src/lists/Streams.js:19 +msgid "There are no events to display at this time" +msgstr "" + #: client/src/lists/PortalJobTemplates.js:20 msgid "There are no job templates to display at this time" msgstr "" @@ -2298,6 +3127,10 @@ msgstr "" msgid "There was an error resetting values. Returned status:" msgstr "" +#: client/src/management-jobs/scheduler/schedulerForm.partial.html:161 +msgid "This is not a valid number." +msgstr "" + #: client/src/helpers/Credentials.js:139 #: client/src/helpers/Credentials.js:275 msgid "This is the tenant name. This value is usually the same as the username." @@ -2307,7 +3140,7 @@ msgstr "" msgid "This list is populated by notification templates added from the %sNotifications%s section" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:199 +#: client/src/notifications/notificationTemplates.form.js:202 msgid "This must be of the form %s." msgstr "" @@ -2325,6 +3158,8 @@ msgid "This will reset all configuration values to their factory defaults. Are y msgstr "" #: client/src/dashboard/lists/jobs/jobs-list.partial.html:14 +#: client/src/lists/Streams.js:28 +#: client/src/notifications/notification-templates-list/list.controller.js:74 msgid "Time" msgstr "" @@ -2336,10 +3171,20 @@ msgstr "" 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 "" +#: client/src/forms/EventsViewer.js:74 +#: client/src/forms/EventsViewer.js:78 +#: client/src/forms/EventsViewer.js:82 +msgid "Timing" +msgstr "" + #: client/src/forms/Credentials.js:126 msgid "To learn more about the IAM STS Token, refer to the %sAmazon documentation%s." msgstr "" +#: client/src/job-detail/job-detail.partial.html:416 +msgid "Toggle Output" +msgstr "" + #: client/src/shared/form-generator.js:855 msgid "Toggle the display of plaintext." msgstr "" @@ -2349,35 +3194,40 @@ msgstr "" msgid "Token" msgstr "" +#: client/src/partials/logviewer.html:6 +msgid "Traceback" +msgstr "" + #: client/src/forms/Credentials.js:61 #: client/src/forms/Credentials.js:85 -#: client/src/forms/Teams.js:130 +#: client/src/forms/Teams.js:129 #: client/src/forms/Users.js:196 #: client/src/forms/WorkflowMaker.js:34 +#: client/src/lists/AllJobs.js:61 #: client/src/lists/CompletedJobs.js:50 #: client/src/lists/Credentials.js:39 #: client/src/lists/Projects.js:43 #: client/src/lists/ScheduledJobs.js:43 #: client/src/lists/Templates.js:31 -#: client/src/notifications/notificationTemplates.form.js:54 -#: client/src/notifications/notificationTemplates.list.js:38 +#: client/src/notifications/notificationTemplates.form.js:57 +#: client/src/notifications/notificationTemplates.list.js:37 #: client/src/notifications/notifications.list.js:31 msgid "Type" msgstr "" #: client/src/forms/Credentials.js:25 -#: client/src/notifications/notificationTemplates.form.js:23 +#: client/src/notifications/notificationTemplates.form.js:26 msgid "Type Details" msgstr "" -#: client/src/notifications/notificationTemplates.form.js:212 -#: client/src/notifications/notificationTemplates.form.js:97 +#: client/src/notifications/notificationTemplates.form.js:100 +#: client/src/notifications/notificationTemplates.form.js:215 msgid "Type an option on each line." msgstr "" -#: client/src/notifications/notificationTemplates.form.js:141 -#: client/src/notifications/notificationTemplates.form.js:158 -#: client/src/notifications/notificationTemplates.form.js:371 +#: client/src/notifications/notificationTemplates.form.js:144 +#: client/src/notifications/notificationTemplates.form.js:161 +#: client/src/notifications/notificationTemplates.form.js:374 msgid "Type an option on each line. The pound symbol (#) is not required." msgstr "" @@ -2390,7 +3240,9 @@ msgstr "" msgid "USERNAME" msgstr "" -#: client/src/app.js:364 +#: client/src/app.js:367 +#: client/src/helpers/ActivityStream.js:32 +#: client/src/organizations/linkout/organizations-linkout.route.js:59 msgid "USERS" msgstr "" @@ -2410,6 +3262,14 @@ msgstr "" msgid "Upgrade" msgstr "" +#: client/src/notifications/notificationTemplates.form.js:407 +msgid "Use SSL" +msgstr "" + +#: client/src/notifications/notificationTemplates.form.js:402 +msgid "Use TLS" +msgstr "" + #: client/src/forms/Credentials.js:77 msgid "Used to check out and synchronize playbook repositories with a remote source control management system such as Git, Subversion (svn), or Mercurial (hg). These credentials are used by Projects." msgstr "" @@ -2420,13 +3280,20 @@ msgstr "" #: client/src/forms/Organizations.js:83 #: client/src/forms/Projects.js:244 #: client/src/forms/Teams.js:93 +#: client/src/forms/Workflows.js:135 +#: client/src/widgets/Stream.js:380 msgid "User" msgstr "" +#: client/src/configuration/configuration.partial.html:18 +msgid "User Interface" +msgstr "" + #: client/src/forms/Users.js:94 msgid "User Type" msgstr "" +#: client/src/access/rbac-multiselect/permissionsUsers.list.js:36 #: client/src/forms/Users.js:49 #: client/src/helpers/Credentials.js:118 #: client/src/helpers/Credentials.js:225 @@ -2435,7 +3302,7 @@ msgstr "" #: client/src/helpers/Credentials.js:56 #: client/src/helpers/Credentials.js:89 #: client/src/lists/Users.js:37 -#: client/src/notifications/notificationTemplates.form.js:64 +#: client/src/notifications/notificationTemplates.form.js:67 msgid "Username" msgstr "" @@ -2443,6 +3310,8 @@ msgstr "" msgid "Usernames, passwords, and access keys for authenticating to the specified cloud or infrastructure provider. These are used for dynamic inventory sources and for cloud provisioning and deployment in playbook runs." msgstr "" +#: client/src/access/add-rbac-resource/rbac-resource.partial.html:35 +#: client/src/activity-stream/streamDropdownNav/stream-dropdown-nav.directive.js:29 #: client/src/forms/Teams.js:75 #: client/src/lists/Users.js:26 #: client/src/lists/Users.js:27 @@ -2477,6 +3346,8 @@ msgstr "" #: client/src/forms/JobTemplates.js:237 #: client/src/forms/JobTemplates.js:244 +#: client/src/job-detail/job-detail.partial.html:148 +#: client/src/standard-out/adhoc/standard-out-adhoc.partial.html:99 msgid "Verbosity" msgstr "" @@ -2489,13 +3360,20 @@ msgstr "" #: client/src/inventory-scripts/inventory-scripts.list.js:65 #: client/src/lists/Credentials.js:81 #: client/src/lists/Inventories.js:85 +#: client/src/lists/JobEvents.js:98 +#: client/src/lists/Schedules.js:84 +#: client/src/lists/Streams.js:66 #: client/src/lists/Teams.js:69 #: client/src/lists/Templates.js:117 #: client/src/lists/Users.js:78 -#: client/src/notifications/notificationTemplates.list.js:81 +#: client/src/notifications/notificationTemplates.list.js:80 msgid "View" msgstr "" +#: client/src/bread-crumb/bread-crumb.directive.js:106 +msgid "View Activity Stream" +msgstr "" + #: client/src/main-menu/main-menu.partial.html:173 msgid "View Documentation" msgstr "" @@ -2526,6 +3404,11 @@ msgstr "" msgid "View credential" msgstr "" +#: client/src/lists/JobEvents.js:100 +#: client/src/lists/Streams.js:70 +msgid "View event details" +msgstr "" + #: client/src/setup-menu/setup-menu.partial.html:60 msgid "View information about this version of Ansible Tower." msgstr "" @@ -2538,10 +3421,14 @@ msgstr "" msgid "View inventory script" msgstr "" -#: client/src/notifications/notificationTemplates.list.js:83 +#: client/src/notifications/notificationTemplates.list.js:82 msgid "View notification" msgstr "" +#: client/src/lists/Schedules.js:86 +msgid "View schedule" +msgstr "" + #: client/src/lists/Teams.js:72 msgid "View team" msgstr "" @@ -2550,6 +3437,10 @@ msgstr "" msgid "View template" msgstr "" +#: client/src/lists/AllJobs.js:94 +msgid "View the job" +msgstr "" + #: client/src/lists/Projects.js:110 msgid "View the project" msgstr "" @@ -2562,10 +3453,20 @@ msgstr "" msgid "View user" msgstr "" +#: client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html:25 +#: client/src/standard-out/scm-update/standard-out-scm-update.partial.html:25 +msgid "View workflow results" +msgstr "" + #: client/src/forms/Workflows.js:22 msgid "WORKFLOW" msgstr "" +#: client/src/job-detail/job-detail.partial.html:313 +#: client/src/job-detail/job-detail.partial.html:368 +msgid "Waiting..." +msgstr "" + #: client/src/configuration/auth-form/configuration-auth.controller.js:68 #: client/src/configuration/configuration.controller.js:179 #: client/src/configuration/configuration.controller.js:241 @@ -2595,10 +3496,23 @@ msgstr "" msgid "Workflow Job Template" msgstr "" +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:103 +#: client/src/access/add-rbac-user-team/rbac-user-team.partial.html:40 +msgid "Workflow Templates" +msgstr "" + +#: client/src/dashboard/lists/job-templates/job-templates-list.partial.html:58 +msgid "You can create a job template here." +msgstr "" + #: client/src/controllers/Projects.js:508 msgid "You do not have access to view this property" msgstr "" +#: client/src/templates/job_templates/add-job-template/job-template-add.controller.js:26 +msgid "You do not have permission to add a job template." +msgstr "" + #: client/src/controllers/Projects.js:324 msgid "You do not have permission to add a project." msgstr "" @@ -2646,6 +3560,18 @@ msgstr "" msgid "and" msgstr "" +#: client/src/access/rbac-multiselect/permissionsTeams.list.js:22 +msgid "name" +msgstr "" + +#: client/src/shared/paginate/paginate.partial.html:41 +msgid "of {{dataCount()}}" +msgstr "" + +#: client/src/access/rbac-multiselect/permissionsTeams.list.js:25 +msgid "organization" +msgstr "" + #: client/src/forms/Credentials.js:139 #: client/src/forms/Credentials.js:365 msgid "set in helpers/credentials" diff --git a/awx/ui/po/fr.po b/awx/ui/po/fr.po index e4d820a8ff..e853fc3f29 100644 --- a/awx/ui/po/fr.po +++ b/awx/ui/po/fr.po @@ -24,7 +24,7 @@ msgid "" " put the username and key in the URL. If using Bitbucket and SSH, do not " "supply your Bitbucket username." msgstr "" -"%Remarque :%s Mercurial ne prend pas en charge l'authentification par mot de" +"%sRemarque%s : Mercurial ne prend pas en charge l'authentification par mot de" " passe pour SSH. N'entrez ni le nom d'utilisateur, ni la clé dans l'URL. Si " "vous utilisez Bitbucket et SSH, ne saisissez pas votre nom d'utilisateur " "Bitbucket." @@ -37,7 +37,7 @@ msgid "" "Bitbucket do not support password authentication when using SSH. GIT read " "only protocol (git://) does not use username or password information." msgstr "" -"%Remarque :%s Si vous utilisez le protocole SSH pour GitHub ou Bitbucket, " +"%sRemarque%s : Si vous utilisez le protocole SSH pour GitHub ou Bitbucket, " "entrez uniquement une clé SSH sans nom d'utilisateur (autre que git). De " "plus, GitHub et Bitbucket ne prennent pas en charge l'authentification par " "mot de passe lorsque SSH est utilisé. Le protocole GIT en lecture seule " diff --git a/docs/build_system.md b/docs/build_system.md index fff0900141..94400a99c2 100644 --- a/docs/build_system.md +++ b/docs/build_system.md @@ -239,7 +239,7 @@ Repositories The nightly repositories are hosted on the AnsibleWorks Jenkins server, and can be found at the following location: - http://jenkins.testing.ansible.com/ansible-tower_nightlies_RTYUIOPOIUYTYU/devel + http://jenkins.testing.ansible.com/ansible-tower_nightlies_f8b8c5588b2505970227a7b0900ef69040ad5a00/devel There are several sub-folders, including `deb/`, `rpm/`, `docs/` and `setup/` @@ -260,7 +260,7 @@ The `setup/` folder contains the Ansible Tower setup playbook tar.gz file. These nightly repositories can be used by the Ansible Tower setup playbook by running the `setup.sh` shell script with the following option: - ./setup.sh -e "aw_repo_url=http://jenkins.testing.ansible.com/ansible-tower_nightlies_RTYUIOPOIUYTYU/devel gpgcheck=0" + ./setup.sh -e "aw_repo_url=http://jenkins.testing.ansible.com/ansible-tower_nightlies_f8b8c5588b2505970227a7b0900ef69040ad5a00/devel gpgcheck=0" ### Official Releases ### diff --git a/tools/docker-compose.yml b/tools/docker-compose.yml index e97591be1e..edcddcbe43 100644 --- a/tools/docker-compose.yml +++ b/tools/docker-compose.yml @@ -9,11 +9,13 @@ services: RABBITMQ_USER: guest RABBITMQ_PASS: guest RABBITMQ_VHOST: / + CELERY_RDB_HOST: 0.0.0.0 ports: - "8080:8080" - "5555:5555" - "8013:8013" - "8043:8043" + - "6899-6999:6899-6999" # default port range for celery.contrib.rdb links: - postgres - memcached diff --git a/tools/docker-compose/unit-tests/docker-compose.yml b/tools/docker-compose/unit-tests/docker-compose.yml index e878fbc419..ec97dcc46d 100644 --- a/tools/docker-compose/unit-tests/docker-compose.yml +++ b/tools/docker-compose/unit-tests/docker-compose.yml @@ -8,7 +8,7 @@ services: image: gcr.io/ansible-tower-engineering/unit-test-runner:latest environment: SWIG_FEATURES: "-cpperraswarn -includeall -I/usr/include/openssl" - TEST_DIRS: awx/main/tests/functional awx/main/tests/unit + TEST_DIRS: awx/main/tests/functional awx/main/tests/unit awx/conf/tests command: ["make test"] volumes: - ../../../:/tower_devel diff --git a/tox.ini b/tox.ini index 14726b2bd0..54effa178f 100644 --- a/tox.ini +++ b/tox.ini @@ -48,7 +48,7 @@ commands = python setup.py develop # coverage run --help # coverage run -p --source awx/main/tests -m pytest {posargs} - py.test awx/main/tests {posargs:-k 'not old'} + py.test awx/main/tests awx/conf/tests {posargs:-k 'not old'} [testenv:ui] deps =