mirror of
https://github.com/ansible/awx.git
synced 2026-01-09 23:12:08 -03:30
django i18n
This commit is contained in:
parent
5e8a7eeb8a
commit
78a8ce9479
1
.gitignore
vendored
1
.gitignore
vendored
@ -106,6 +106,7 @@ reports
|
||||
*.log.[0-9]
|
||||
*.results
|
||||
local/
|
||||
*.mo
|
||||
|
||||
# AWX python libs populated by requirements.txt
|
||||
awx/lib/.deps_built
|
||||
|
||||
21
Makefile
21
Makefile
@ -493,6 +493,25 @@ test_tox:
|
||||
# Alias existing make target so old versions run against Jekins the same way
|
||||
test_jenkins : test_coverage
|
||||
|
||||
# l10n TASKS
|
||||
# --------------------------------------
|
||||
|
||||
LANG = "en-us"
|
||||
messages:
|
||||
@if [ "$(VENV_BASE)" ]; then \
|
||||
. $(VENV_BASE)/tower/bin/activate; \
|
||||
fi; \
|
||||
$(PYTHON) manage.py makemessages -l $(LANG)
|
||||
|
||||
languages:
|
||||
@if [ "$(VENV_BASE)" ]; then \
|
||||
. $(VENV_BASE)/tower/bin/activate; \
|
||||
fi; \
|
||||
$(PYTHON) manage.py compilemessages
|
||||
|
||||
# End l10n TASKS
|
||||
# --------------------------------------
|
||||
|
||||
# UI TASKS
|
||||
# --------------------------------------
|
||||
|
||||
@ -506,7 +525,7 @@ ui-docker-machine: $(UI_DEPS_FLAG_FILE)
|
||||
ui-docker: $(UI_DEPS_FLAG_FILE)
|
||||
$(NPM_BIN) --prefix awx/ui run build-docker-cid
|
||||
|
||||
ui-release: $(UI_RELEASE_FLAG_FILE)
|
||||
ui-release: languages $(UI_RELEASE_FLAG_FILE)
|
||||
|
||||
$(UI_RELEASE_FLAG_FILE): $(UI_DEPS_FLAG_FILE)
|
||||
$(NPM_BIN) --prefix awx/ui run build-release
|
||||
|
||||
@ -7,6 +7,7 @@ from collections import OrderedDict
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import Http404
|
||||
from django.utils.encoding import force_text, smart_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework import exceptions
|
||||
@ -46,15 +47,15 @@ class Metadata(metadata.SimpleMetadata):
|
||||
serializer = getattr(field, 'parent', None)
|
||||
if serializer:
|
||||
field_help_text = {
|
||||
'id': 'Database ID for this {}.',
|
||||
'name': 'Name of this {}.',
|
||||
'description': 'Optional description of this {}.',
|
||||
'type': 'Data type for this {}.',
|
||||
'url': 'URL for this {}.',
|
||||
'related': 'Data structure with URLs of related resources.',
|
||||
'summary_fields': 'Data structure with name/description for related resources.',
|
||||
'created': 'Timestamp when this {} was created.',
|
||||
'modified': 'Timestamp when this {} was last modified.',
|
||||
'id': _('Database ID for this {}.'),
|
||||
'name': _('Name of this {}.'),
|
||||
'description': _('Optional description of this {}.'),
|
||||
'type': _('Data type for this {}.'),
|
||||
'url': _('URL for this {}.'),
|
||||
'related': _('Data structure with URLs of related resources.'),
|
||||
'summary_fields': _('Data structure with name/description for related resources.'),
|
||||
'created': _('Timestamp when this {} was created.'),
|
||||
'modified': _('Timestamp when this {} was last modified.'),
|
||||
}
|
||||
if field.field_name in field_help_text:
|
||||
if hasattr(serializer, 'Meta') and hasattr(serializer.Meta, 'model'):
|
||||
|
||||
@ -20,7 +20,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
|
||||
from django.db import models
|
||||
# from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.text import capfirst
|
||||
|
||||
@ -694,9 +694,9 @@ class UnifiedJobStdoutSerializer(UnifiedJobSerializer):
|
||||
class UserSerializer(BaseSerializer):
|
||||
|
||||
password = serializers.CharField(required=False, default='', write_only=True,
|
||||
help_text='Write-only field used to change the password.')
|
||||
help_text=_('Write-only field used to change the password.'))
|
||||
ldap_dn = serializers.CharField(source='profile.ldap_dn', read_only=True)
|
||||
external_account = serializers.SerializerMethodField(help_text='Set if the account is managed by an external service')
|
||||
external_account = serializers.SerializerMethodField(help_text=_('Set if the account is managed by an external service'))
|
||||
is_system_auditor = serializers.BooleanField(default=False)
|
||||
show_capabilities = ['edit', 'delete']
|
||||
|
||||
@ -961,7 +961,7 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
|
||||
|
||||
class ProjectPlaybooksSerializer(ProjectSerializer):
|
||||
|
||||
playbooks = serializers.ReadOnlyField(help_text='Array of playbooks available within this project.')
|
||||
playbooks = serializers.ReadOnlyField(help_text=_('Array of playbooks available within this project.'))
|
||||
|
||||
class Meta:
|
||||
model = Project
|
||||
@ -1717,18 +1717,18 @@ class CredentialSerializerCreate(CredentialSerializer):
|
||||
user = serializers.PrimaryKeyRelatedField(
|
||||
queryset=User.objects.all(),
|
||||
required=False, default=None, write_only=True, allow_null=True,
|
||||
help_text='Write-only field used to add user to owner role. If provided, '
|
||||
'do not give either team or organization. Only valid for creation.')
|
||||
help_text=_('Write-only field used to add user to owner role. If provided, '
|
||||
'do not give either team or organization. Only valid for creation.'))
|
||||
team = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Team.objects.all(),
|
||||
required=False, default=None, write_only=True, allow_null=True,
|
||||
help_text='Write-only field used to add team to owner role. If provided, '
|
||||
'do not give either user or organization. Only valid for creation.')
|
||||
help_text=_('Write-only field used to add team to owner role. If provided, '
|
||||
'do not give either user or organization. Only valid for creation.'))
|
||||
organization = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Organization.objects.all(),
|
||||
required=False, default=None, write_only=True, allow_null=True,
|
||||
help_text='Write-only field used to add organization to owner role. If provided, '
|
||||
'do not give either team or team. Only valid for creation.')
|
||||
help_text=_('Write-only field used to add organization to owner role. If provided, '
|
||||
'do not give either team or team. Only valid for creation.'))
|
||||
|
||||
class Meta:
|
||||
model = Credential
|
||||
@ -2791,15 +2791,15 @@ class ActivityStreamSerializer(BaseSerializer):
|
||||
ret = super(ActivityStreamSerializer, self).get_fields()
|
||||
for key, field in ret.items():
|
||||
if key == 'changes':
|
||||
field.help_text = 'A summary of the new and changed values when an object is created, updated, or deleted'
|
||||
field.help_text = _('A summary of the new and changed values when an object is created, updated, or deleted')
|
||||
if key == 'object1':
|
||||
field.help_text = ('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.')
|
||||
field.help_text = _('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.')
|
||||
if key == 'object2':
|
||||
field.help_text = ('Unpopulated for create, update, and delete events. For associate and disassociate '
|
||||
'events this is the object type that object1 is being associated with.')
|
||||
field.help_text = _('Unpopulated for create, update, and delete events. For associate and disassociate '
|
||||
'events this is the object type that object1 is being associated with.')
|
||||
if key == 'operation':
|
||||
field.help_text = 'The action taken with respect to the given object(s).'
|
||||
field.help_text = _('The action taken with respect to the given object(s).')
|
||||
return ret
|
||||
|
||||
def get_changes(self, obj):
|
||||
|
||||
@ -29,6 +29,7 @@ from django.template.loader import render_to_string
|
||||
from django.core.servers.basehttp import FileWrapper
|
||||
from django.http import HttpResponse
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
# Django REST Framework
|
||||
@ -86,14 +87,14 @@ class ApiRootView(APIView):
|
||||
|
||||
authentication_classes = []
|
||||
permission_classes = (AllowAny,)
|
||||
view_name = 'REST API'
|
||||
view_name = _('REST API')
|
||||
|
||||
def get(self, request, format=None):
|
||||
''' list supported API versions '''
|
||||
|
||||
current = reverse('api:api_v1_root_view', args=[])
|
||||
data = dict(
|
||||
description = 'Ansible Tower REST API',
|
||||
description = _('Ansible Tower REST API'),
|
||||
current_version = current,
|
||||
available_versions = dict(
|
||||
v1 = current
|
||||
@ -105,7 +106,7 @@ class ApiV1RootView(APIView):
|
||||
|
||||
authentication_classes = []
|
||||
permission_classes = (AllowAny,)
|
||||
view_name = 'Version 1'
|
||||
view_name = _('Version 1')
|
||||
|
||||
def get(self, request, format=None):
|
||||
''' list top level resources '''
|
||||
@ -156,7 +157,7 @@ class ApiV1PingView(APIView):
|
||||
"""
|
||||
permission_classes = (AllowAny,)
|
||||
authentication_classes = ()
|
||||
view_name = 'Ping'
|
||||
view_name = _('Ping')
|
||||
new_in_210 = True
|
||||
|
||||
def get(self, request, format=None):
|
||||
@ -182,7 +183,7 @@ class ApiV1PingView(APIView):
|
||||
class ApiV1ConfigView(APIView):
|
||||
|
||||
permission_classes = (IsAuthenticated,)
|
||||
view_name = 'Configuration'
|
||||
view_name = _('Configuration')
|
||||
|
||||
def get(self, request, format=None):
|
||||
'''Return various sitewide configuration settings.'''
|
||||
@ -278,7 +279,7 @@ class ApiV1ConfigView(APIView):
|
||||
|
||||
class DashboardView(APIView):
|
||||
|
||||
view_name = "Dashboard"
|
||||
view_name = _("Dashboard")
|
||||
new_in_14 = True
|
||||
|
||||
def get(self, request, format=None):
|
||||
@ -383,7 +384,7 @@ class DashboardView(APIView):
|
||||
|
||||
class DashboardJobsGraphView(APIView):
|
||||
|
||||
view_name = "Dashboard Jobs Graphs"
|
||||
view_name = _("Dashboard Jobs Graphs")
|
||||
new_in_200 = True
|
||||
|
||||
def get(self, request, format=None):
|
||||
@ -433,7 +434,7 @@ class DashboardJobsGraphView(APIView):
|
||||
|
||||
class ScheduleList(ListAPIView):
|
||||
|
||||
view_name = "Schedules"
|
||||
view_name = _("Schedules")
|
||||
model = Schedule
|
||||
serializer_class = ScheduleSerializer
|
||||
new_in_148 = True
|
||||
@ -450,7 +451,7 @@ class ScheduleUnifiedJobsList(SubListAPIView):
|
||||
serializer_class = UnifiedJobSerializer
|
||||
parent_model = Schedule
|
||||
relationship = 'unifiedjob_set'
|
||||
view_name = 'Schedule Jobs List'
|
||||
view_name = _('Schedule Jobs List')
|
||||
new_in_148 = True
|
||||
|
||||
class AuthView(APIView):
|
||||
@ -998,7 +999,7 @@ class ProjectTeamsList(ListAPIView):
|
||||
|
||||
class ProjectSchedulesList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
view_name = "Project Schedules"
|
||||
view_name = _("Project Schedules")
|
||||
|
||||
model = Schedule
|
||||
serializer_class = ScheduleSerializer
|
||||
@ -1162,7 +1163,7 @@ class UserMeList(ListAPIView):
|
||||
|
||||
model = User
|
||||
serializer_class = UserSerializer
|
||||
view_name = 'Me'
|
||||
view_name = _('Me')
|
||||
|
||||
def get_queryset(self):
|
||||
return self.model.objects.filter(pk=self.request.user.pk)
|
||||
@ -2038,7 +2039,7 @@ class InventoryInventorySourcesList(SubListAPIView):
|
||||
serializer_class = InventorySourceSerializer
|
||||
parent_model = Inventory
|
||||
relationship = None # Not defined since using get_queryset().
|
||||
view_name = 'Inventory Source List'
|
||||
view_name = _('Inventory Source List')
|
||||
new_in_14 = True
|
||||
|
||||
def get_queryset(self):
|
||||
@ -2071,7 +2072,7 @@ class InventorySourceDetail(RetrieveUpdateAPIView):
|
||||
|
||||
class InventorySourceSchedulesList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
view_name = "Inventory Source Schedules"
|
||||
view_name = _("Inventory Source Schedules")
|
||||
|
||||
model = Schedule
|
||||
serializer_class = ScheduleSerializer
|
||||
@ -2292,7 +2293,7 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
|
||||
|
||||
class JobTemplateSchedulesList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
view_name = "Job Template Schedules"
|
||||
view_name = _("Job Template Schedules")
|
||||
|
||||
model = Schedule
|
||||
serializer_class = ScheduleSerializer
|
||||
@ -2823,7 +2824,7 @@ class SystemJobTemplateLaunch(GenericAPIView):
|
||||
|
||||
class SystemJobTemplateSchedulesList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
view_name = "System Job Template Schedules"
|
||||
view_name = _("System Job Template Schedules")
|
||||
|
||||
model = Schedule
|
||||
serializer_class = ScheduleSerializer
|
||||
@ -2991,7 +2992,7 @@ class BaseJobHostSummariesList(SubListAPIView):
|
||||
serializer_class = JobHostSummarySerializer
|
||||
parent_model = None # Subclasses must define this attribute.
|
||||
relationship = 'job_host_summaries'
|
||||
view_name = 'Job Host Summaries List'
|
||||
view_name = _('Job Host Summaries List')
|
||||
|
||||
class HostJobHostSummariesList(BaseJobHostSummariesList):
|
||||
|
||||
@ -3026,7 +3027,7 @@ class JobEventChildrenList(SubListAPIView):
|
||||
serializer_class = JobEventSerializer
|
||||
parent_model = JobEvent
|
||||
relationship = 'children'
|
||||
view_name = 'Job Event Children List'
|
||||
view_name = _('Job Event Children List')
|
||||
|
||||
class JobEventHostsList(SubListAPIView):
|
||||
|
||||
@ -3034,7 +3035,7 @@ class JobEventHostsList(SubListAPIView):
|
||||
serializer_class = HostSerializer
|
||||
parent_model = JobEvent
|
||||
relationship = 'hosts'
|
||||
view_name = 'Job Event Hosts List'
|
||||
view_name = _('Job Event Hosts List')
|
||||
|
||||
class BaseJobEventsList(SubListAPIView):
|
||||
|
||||
@ -3042,7 +3043,7 @@ class BaseJobEventsList(SubListAPIView):
|
||||
serializer_class = JobEventSerializer
|
||||
parent_model = None # Subclasses must define this attribute.
|
||||
relationship = 'job_events'
|
||||
view_name = 'Job Events List'
|
||||
view_name = _('Job Events List')
|
||||
|
||||
class HostJobEventsList(BaseJobEventsList):
|
||||
|
||||
@ -3074,7 +3075,7 @@ class JobJobEventsList(BaseJobEventsList):
|
||||
class JobJobPlaysList(BaseJobEventsList):
|
||||
|
||||
parent_model = Job
|
||||
view_name = 'Job Plays List'
|
||||
view_name = _('Job Plays List')
|
||||
new_in_200 = True
|
||||
|
||||
@paginated
|
||||
@ -3149,7 +3150,7 @@ class JobJobTasksList(BaseJobEventsList):
|
||||
and their completion status.
|
||||
"""
|
||||
parent_model = Job
|
||||
view_name = 'Job Play Tasks List'
|
||||
view_name = _('Job Play Tasks List')
|
||||
new_in_200 = True
|
||||
|
||||
@paginated
|
||||
@ -3444,7 +3445,7 @@ class BaseAdHocCommandEventsList(SubListAPIView):
|
||||
serializer_class = AdHocCommandEventSerializer
|
||||
parent_model = None # Subclasses must define this attribute.
|
||||
relationship = 'ad_hoc_command_events'
|
||||
view_name = 'Ad Hoc Command Events List'
|
||||
view_name = _('Ad Hoc Command Events List')
|
||||
new_in_220 = True
|
||||
|
||||
|
||||
@ -3660,7 +3661,7 @@ class NotificationTemplateDetail(RetrieveUpdateDestroyAPIView):
|
||||
|
||||
class NotificationTemplateTest(GenericAPIView):
|
||||
|
||||
view_name = 'NotificationTemplate Test'
|
||||
view_name = _('NotificationTemplate Test')
|
||||
model = NotificationTemplate
|
||||
serializer_class = EmptySerializer
|
||||
new_in_300 = True
|
||||
|
||||
@ -11,6 +11,7 @@ from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework.exceptions import ParseError, PermissionDenied, ValidationError
|
||||
@ -199,24 +200,24 @@ class BaseAccess(object):
|
||||
validation_info['grace_period_remaining'] = 99999999
|
||||
|
||||
if check_expiration and validation_info.get('time_remaining', None) is None:
|
||||
raise PermissionDenied("License is missing.")
|
||||
raise PermissionDenied(_("License is missing."))
|
||||
if check_expiration and validation_info.get("grace_period_remaining") <= 0:
|
||||
raise PermissionDenied("License has expired.")
|
||||
raise PermissionDenied(_("License has expired."))
|
||||
|
||||
free_instances = validation_info.get('free_instances', 0)
|
||||
available_instances = validation_info.get('available_instances', 0)
|
||||
if add_host and free_instances == 0:
|
||||
raise PermissionDenied("License count of %s instances has been reached." % available_instances)
|
||||
raise PermissionDenied(_("License count of %s instances has been reached.") % available_instances)
|
||||
elif add_host and free_instances < 0:
|
||||
raise PermissionDenied("License count of %s instances has been exceeded." % available_instances)
|
||||
raise PermissionDenied(_("License count of %s instances has been exceeded.") % available_instances)
|
||||
elif not add_host and free_instances < 0:
|
||||
raise PermissionDenied("Host count exceeds available instances.")
|
||||
raise PermissionDenied(_("Host count exceeds available instances."))
|
||||
|
||||
if feature is not None:
|
||||
if "features" in validation_info and not validation_info["features"].get(feature, False):
|
||||
raise LicenseForbids("Feature %s is not enabled in the active license." % feature)
|
||||
raise LicenseForbids(_("Feature %s is not enabled in the active license.") % feature)
|
||||
elif "features" not in validation_info:
|
||||
raise LicenseForbids("Features not found in active license.")
|
||||
raise LicenseForbids(_("Features not found in active license."))
|
||||
|
||||
def get_user_capabilities(self, obj, method_list=[], parent_obj=None):
|
||||
if obj is None:
|
||||
@ -535,7 +536,7 @@ class HostAccess(BaseAccess):
|
||||
# Prevent moving a host to a different inventory.
|
||||
inventory_pk = get_pk_from_dict(data, 'inventory')
|
||||
if obj and inventory_pk and obj.inventory.pk != inventory_pk:
|
||||
raise PermissionDenied('Unable to change inventory on a host.')
|
||||
raise PermissionDenied(_('Unable to change inventory on a host.'))
|
||||
# Checks for admin or change permission on inventory, controls whether
|
||||
# the user can edit variable data.
|
||||
return obj and self.user in obj.inventory.admin_role
|
||||
@ -547,7 +548,7 @@ class HostAccess(BaseAccess):
|
||||
return False
|
||||
# Prevent assignments between different inventories.
|
||||
if obj.inventory != sub_obj.inventory:
|
||||
raise ParseError('Cannot associate two items from different inventories.')
|
||||
raise ParseError(_('Cannot associate two items from different inventories.'))
|
||||
return True
|
||||
|
||||
def can_delete(self, obj):
|
||||
@ -581,7 +582,7 @@ class GroupAccess(BaseAccess):
|
||||
# Prevent moving a group to a different inventory.
|
||||
inventory_pk = get_pk_from_dict(data, 'inventory')
|
||||
if obj and inventory_pk and obj.inventory.pk != inventory_pk:
|
||||
raise PermissionDenied('Unable to change inventory on a group.')
|
||||
raise PermissionDenied(_('Unable to change inventory on a group.'))
|
||||
# Checks for admin or change permission on inventory, controls whether
|
||||
# the user can attach subgroups or edit variable data.
|
||||
return obj and self.user in obj.inventory.admin_role
|
||||
@ -593,7 +594,7 @@ class GroupAccess(BaseAccess):
|
||||
return False
|
||||
# Prevent assignments between different inventories.
|
||||
if obj.inventory != sub_obj.inventory:
|
||||
raise ParseError('Cannot associate two items from different inventories.')
|
||||
raise ParseError(_('Cannot associate two items from different inventories.'))
|
||||
# Prevent group from being assigned as its own (grand)child.
|
||||
if type(obj) == type(sub_obj):
|
||||
parent_pks = set(obj.all_parents.values_list('pk', flat=True))
|
||||
@ -805,7 +806,7 @@ class TeamAccess(BaseAccess):
|
||||
# Prevent moving a team to a different organization.
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
if obj and org_pk and obj.organization.pk != org_pk:
|
||||
raise PermissionDenied('Unable to change organization on a team.')
|
||||
raise PermissionDenied(_('Unable to change organization on a team.'))
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return self.user in obj.admin_role
|
||||
@ -818,9 +819,9 @@ class TeamAccess(BaseAccess):
|
||||
of a resource role to the team."""
|
||||
if isinstance(sub_obj, Role):
|
||||
if sub_obj.content_object is None:
|
||||
raise PermissionDenied("The {} role cannot be assigned to a team".format(sub_obj.name))
|
||||
raise PermissionDenied(_("The {} role cannot be assigned to a team").format(sub_obj.name))
|
||||
elif isinstance(sub_obj.content_object, User):
|
||||
raise PermissionDenied("The admin_role for a User cannot be assigned to a team")
|
||||
raise PermissionDenied(_("The admin_role for a User cannot be assigned to a team"))
|
||||
|
||||
if isinstance(sub_obj.content_object, ResourceMixin):
|
||||
role_access = RoleAccess(self.user)
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
# Django
|
||||
from django.shortcuts import render
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework import exceptions, permissions, views
|
||||
@ -16,7 +17,7 @@ class ApiErrorView(views.APIView):
|
||||
metadata_class = None
|
||||
allowed_methods = ('GET', 'HEAD')
|
||||
exception_class = exceptions.APIException
|
||||
view_name = 'API Error'
|
||||
view_name = _('API Error')
|
||||
|
||||
def get_view_name(self):
|
||||
return self.view_name
|
||||
@ -45,31 +46,31 @@ def handle_error(request, status=404, **kwargs):
|
||||
|
||||
def handle_400(request):
|
||||
kwargs = {
|
||||
'name': 'Bad Request',
|
||||
'content': 'The request could not be understood by the server.',
|
||||
'name': _('Bad Request'),
|
||||
'content': _('The request could not be understood by the server.'),
|
||||
}
|
||||
return handle_error(request, 400, **kwargs)
|
||||
|
||||
|
||||
def handle_403(request):
|
||||
kwargs = {
|
||||
'name': 'Forbidden',
|
||||
'content': 'You don\'t have permission to access the requested resource.',
|
||||
'name': _('Forbidden'),
|
||||
'content': _('You don\'t have permission to access the requested resource.'),
|
||||
}
|
||||
return handle_error(request, 403, **kwargs)
|
||||
|
||||
|
||||
def handle_404(request):
|
||||
kwargs = {
|
||||
'name': 'Not Found',
|
||||
'content': 'The requested resource could not be found.',
|
||||
'name': _('Not Found'),
|
||||
'content': _('The requested resource could not be found.'),
|
||||
}
|
||||
return handle_error(request, 404, **kwargs)
|
||||
|
||||
|
||||
def handle_500(request):
|
||||
kwargs = {
|
||||
'name': 'Server Error',
|
||||
'content': 'A server error has occurred.',
|
||||
'name': _('Server Error'),
|
||||
'content': _('A server error has occurred.'),
|
||||
}
|
||||
return handle_error(request, 500, **kwargs)
|
||||
|
||||
@ -18,6 +18,9 @@ for setting in dir(global_settings):
|
||||
if setting == setting.upper():
|
||||
setattr(this_module, setting, getattr(global_settings, setting))
|
||||
|
||||
# gettext
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
@ -118,6 +121,11 @@ LOG_ROOT = os.path.join(BASE_DIR)
|
||||
# The heartbeat file for the tower scheduler
|
||||
SCHEDULE_METADATA_LOCATION = os.path.join(BASE_DIR, '.tower_cycle')
|
||||
|
||||
# Django gettext files path: locale/<lang-code>/LC_MESSAGES/django.po, django.mo
|
||||
LOCALE_PATHS = (
|
||||
os.path.join(BASE_DIR, 'locale'),
|
||||
)
|
||||
|
||||
# Maximum number of the same job that can be waiting to run when launching from scheduler
|
||||
# Note: This setting may be overridden by database settings.
|
||||
SCHEDULE_MAX_JOBS = 10
|
||||
@ -155,8 +163,9 @@ TEMPLATE_CONTEXT_PROCESSORS = ( # NOQA
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = ( # NOQA
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
@ -560,12 +569,12 @@ AD_HOC_COMMANDS = [
|
||||
# instead (based on docs from:
|
||||
# http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/Service_Access_Endpoints-d1e517.html)
|
||||
RAX_REGION_CHOICES = [
|
||||
('ORD', 'Chicago'),
|
||||
('DFW', 'Dallas/Ft. Worth'),
|
||||
('IAD', 'Northern Virginia'),
|
||||
('LON', 'London'),
|
||||
('SYD', 'Sydney'),
|
||||
('HKG', 'Hong Kong'),
|
||||
('ORD', _('Chicago')),
|
||||
('DFW', _('Dallas/Ft. Worth')),
|
||||
('IAD', _('Northern Virginia')),
|
||||
('LON', _('London')),
|
||||
('SYD', _('Sydney')),
|
||||
('HKG', _('Hong Kong')),
|
||||
]
|
||||
|
||||
# Inventory variable name/values for determining if host is active/enabled.
|
||||
@ -592,18 +601,18 @@ INV_ENV_VARIABLE_BLACKLIST = ("HOME", "USER", "_", "TERM")
|
||||
# list of names here. The available region IDs will be pulled from boto.
|
||||
# http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region
|
||||
EC2_REGION_NAMES = {
|
||||
'us-east-1': 'US East (Northern Virginia)',
|
||||
'us-west-2': 'US West (Oregon)',
|
||||
'us-west-1': 'US West (Northern California)',
|
||||
'eu-central-1': 'EU (Frankfurt)',
|
||||
'eu-west-1': 'EU (Ireland)',
|
||||
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
||||
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
||||
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
||||
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
||||
'sa-east-1': 'South America (Sao Paulo)',
|
||||
'us-gov-west-1': 'US West (GovCloud)',
|
||||
'cn-north-1': 'China (Beijing)',
|
||||
'us-east-1': _('US East (Northern Virginia)'),
|
||||
'us-west-2': _('US West (Oregon)'),
|
||||
'us-west-1': _('US West (Northern California)'),
|
||||
'eu-central-1': _('EU (Frankfurt)'),
|
||||
'eu-west-1': _('EU (Ireland)'),
|
||||
'ap-southeast-1': _('Asia Pacific (Singapore)'),
|
||||
'ap-southeast-2': _('Asia Pacific (Sydney)'),
|
||||
'ap-northeast-1': _('Asia Pacific (Tokyo)'),
|
||||
'ap-northeast-2': _('Asia Pacific (Seoul)'),
|
||||
'sa-east-1': _('South America (Sao Paulo)'),
|
||||
'us-gov-west-1': _('US West (GovCloud)'),
|
||||
'cn-north-1': _('China (Beijing)'),
|
||||
}
|
||||
|
||||
EC2_REGIONS_BLACKLIST = [
|
||||
@ -652,19 +661,19 @@ VMWARE_EXCLUDE_EMPTY_GROUPS = True
|
||||
# provide a list here.
|
||||
# Source: https://developers.google.com/compute/docs/zones
|
||||
GCE_REGION_CHOICES = [
|
||||
('us-east1-b', 'US East (B)'),
|
||||
('us-east1-c', 'US East (C)'),
|
||||
('us-east1-d', 'US East (D)'),
|
||||
('us-central1-a', 'US Central (A)'),
|
||||
('us-central1-b', 'US Central (B)'),
|
||||
('us-central1-c', 'US Central (C)'),
|
||||
('us-central1-f', 'US Central (F)'),
|
||||
('europe-west1-b', 'Europe West (B)'),
|
||||
('europe-west1-c', 'Europe West (C)'),
|
||||
('europe-west1-d', 'Europe West (D)'),
|
||||
('asia-east1-a', 'Asia East (A)'),
|
||||
('asia-east1-b', 'Asia East (B)'),
|
||||
('asia-east1-c', 'Asia East (C)'),
|
||||
('us-east1-b', _('US East (B)')),
|
||||
('us-east1-c', _('US East (C)')),
|
||||
('us-east1-d', _('US East (D)')),
|
||||
('us-central1-a', _('US Central (A)')),
|
||||
('us-central1-b', _('US Central (B)')),
|
||||
('us-central1-c', _('US Central (C)')),
|
||||
('us-central1-f', _('US Central (F)')),
|
||||
('europe-west1-b', _('Europe West (B)')),
|
||||
('europe-west1-c', _('Europe West (C)')),
|
||||
('europe-west1-d', _('Europe West (D)')),
|
||||
('asia-east1-a', _('Asia East (A)')),
|
||||
('asia-east1-b', _('Asia East (B)')),
|
||||
('asia-east1-c', _('Asia East (C)')),
|
||||
]
|
||||
GCE_REGIONS_BLACKLIST = []
|
||||
|
||||
@ -688,19 +697,19 @@ GCE_INSTANCE_ID_VAR = None
|
||||
# It's not possible to get zones in Azure without authenticating, so we
|
||||
# provide a list here.
|
||||
AZURE_REGION_CHOICES = [
|
||||
('Central_US', 'US Central'),
|
||||
('East_US_1', 'US East'),
|
||||
('East_US_2', 'US East 2'),
|
||||
('North_Central_US', 'US North Central'),
|
||||
('South_Central_US', 'US South Central'),
|
||||
('West_US', 'US West'),
|
||||
('North_Europe', 'Europe North'),
|
||||
('West_Europe', 'Europe West'),
|
||||
('East_Asia_Pacific', 'Asia Pacific East'),
|
||||
('Southest_Asia_Pacific', 'Asia Pacific Southeast'),
|
||||
('East_Japan', 'Japan East'),
|
||||
('West_Japan', 'Japan West'),
|
||||
('South_Brazil', 'Brazil South'),
|
||||
('Central_US', _('US Central')),
|
||||
('East_US_1', _('US East')),
|
||||
('East_US_2', _('US East 2')),
|
||||
('North_Central_US', _('US North Central')),
|
||||
('South_Central_US', _('US South Central')),
|
||||
('West_US', _('US West')),
|
||||
('North_Europe', _('Europe North')),
|
||||
('West_Europe', _('Europe West')),
|
||||
('East_Asia_Pacific', _('Asia Pacific East')),
|
||||
('Southest_Asia_Pacific', _('Asia Pacific Southeast')),
|
||||
('East_Japan', _('Japan East')),
|
||||
('West_Japan', _('Japan West')),
|
||||
('South_Brazil', _('Brazil South')),
|
||||
]
|
||||
AZURE_REGIONS_BLACKLIST = []
|
||||
|
||||
|
||||
@ -7,6 +7,9 @@ import re
|
||||
# Python Social Auth
|
||||
from social.exceptions import AuthException
|
||||
|
||||
# Django
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Tower
|
||||
from awx.conf.license import feature_enabled
|
||||
|
||||
@ -18,13 +21,13 @@ class AuthNotFound(AuthException):
|
||||
super(AuthNotFound, self).__init__(backend, *args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return 'An account cannot be found for {0}'.format(self.email_or_uid)
|
||||
return _('An account cannot be found for {0}').format(self.email_or_uid)
|
||||
|
||||
|
||||
class AuthInactive(AuthException):
|
||||
|
||||
def __str__(self):
|
||||
return 'Your account is inactive'
|
||||
return _('Your account is inactive')
|
||||
|
||||
|
||||
def check_user_found_or_created(backend, details, user=None, *args, **kwargs):
|
||||
|
||||
@ -36,9 +36,9 @@
|
||||
{% if user.is_authenticated %}
|
||||
<li><a href="{% url 'api:user_me_list' %}" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Logged in as {{ user }}{% if user.get_full_name %} ({{ user.get_full_name }}){% endif %}"><span class="glyphicon glyphicon-user"></span> <span class="visible-xs-inline">Logged in as </span>{{ user }}{% if user.get_full_name %}<span class="visible-xs-inline"> ({{ user.get_full_name }})</span>{% endif %}</a></li>
|
||||
{% endif %}
|
||||
<li><a href="//docs.ansible.com/ansible-tower/{{short_tower_version}}/html/towerapi/index.html" target="_blank" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Ansible Tower API Guide"><span class="glyphicon glyphicon-question-sign"></span><span class="visible-xs-inline"> Ansible Tower API Guide</span></a></li>
|
||||
<li><a href="/" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Back to Ansible Tower"><span class="glyphicon glyphicon-circle-arrow-left"></span><span class="visible-xs-inline"> Back to Ansible Tower</span></a></li>
|
||||
<li class="hidden-xs"><a href="#" class="resize" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Resize"><span class="glyphicon glyphicon-resize-full"></span></a></li>
|
||||
<li><a href="//docs.ansible.com/ansible-tower/{{short_tower_version}}/html/towerapi/index.html" target="_blank" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Ansible Tower API Guide' %}"><span class="glyphicon glyphicon-question-sign"></span><span class="visible-xs-inline">{% trans 'Ansible Tower API Guide' %}</span></a></li>
|
||||
<li><a href="/" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Back to Ansible Tower' %}"><span class="glyphicon glyphicon-circle-arrow-left"></span><span class="visible-xs-inline">{% trans 'Back to Ansible Tower' %}</span></a></li>
|
||||
<li class="hidden-xs"><a href="#" class="resize" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Resize' %}"><span class="glyphicon glyphicon-resize-full"></span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
{# Copy of base.html from rest_framework with minor Ansible Tower change. #}
|
||||
{% load staticfiles %}
|
||||
{% load rest_framework %}
|
||||
{% load i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{% block head %}
|
||||
@ -75,21 +75,21 @@
|
||||
<fieldset>
|
||||
{% if api_settings.URL_FORMAT_OVERRIDE %}
|
||||
<div class="btn-group format-selection">
|
||||
<a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a>
|
||||
<a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="{% blocktrans %}Make a GET request on the {{ name }} resource{% endblocktrans %}">GET</a>
|
||||
|
||||
<button class="btn btn-primary dropdown-toggle js-tooltip" data-toggle="dropdown" title="Specify a format for the GET request">
|
||||
<button class="btn btn-primary dropdown-toggle js-tooltip" data-toggle="dropdown" title="{% trans 'Specify a format for the GET request' %}">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{% for format in available_formats %}
|
||||
<li>
|
||||
<a class="js-tooltip format-option" href="{% add_query_param request api_settings.URL_FORMAT_OVERRIDE format %}" rel="nofollow" title="Make a GET request on the {{ name }} resource with the format set to `{{ format }}`">{{ format }}</a>
|
||||
<a class="js-tooltip format-option" href="{% add_query_param request api_settings.URL_FORMAT_OVERRIDE format %}" rel="nofollow" title="{% blocktrans %}Make a GET request on the {{ name }} resource with the format set to `{{ format }}`{% endblocktrans %}">{{ format }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a>
|
||||
<a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="{% blocktrans %}Make a GET request on the {{ name }} resource{% endblocktrans %}">GET</a>
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
</form>
|
||||
@ -97,13 +97,13 @@
|
||||
|
||||
{% if options_form %}
|
||||
<form class="button-form" action="{{ request.get_full_path }}" data-method="OPTIONS">
|
||||
<button class="btn btn-primary js-tooltip" title="Make an OPTIONS request on the {{ name }} resource">OPTIONS</button>
|
||||
<button class="btn btn-primary js-tooltip" title="{% blocktrans %}Make an OPTIONS request on the {{ name }} resource{% endblocktrans %}">OPTIONS</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% if delete_form %}
|
||||
<form class="button-form" action="{{ request.get_full_path }}" data-method="DELETE">
|
||||
<button class="btn btn-danger js-tooltip" title="Make a DELETE request on the {{ name }} resource">DELETE</button>
|
||||
<button class="btn btn-danger js-tooltip" title="{% blocktrans %}Make a DELETE request on the {{ name }} resource{% endblocktrans %}">DELETE</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
@ -169,7 +169,7 @@
|
||||
{% csrf_token %}
|
||||
{{ post_form }}
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-primary" title="Make a POST request on the {{ name }} resource">POST</button>
|
||||
<button class="btn btn-primary" title="{% blocktrans %}Make a POST request on the {{ name }} resource{% endblocktrans %}">POST</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
@ -183,7 +183,7 @@
|
||||
<fieldset>
|
||||
{% include "rest_framework/raw_data_form.html" %}
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-primary" title="Make a POST request on the {{ name }} resource">POST</button>
|
||||
<button class="btn btn-primary" title="{% blocktrans %}Make a POST request on the {{ name }} resource{% endblocktrans %}">POST</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
@ -213,7 +213,7 @@
|
||||
<fieldset>
|
||||
{{ put_form }}
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-primary js-tooltip" title="Make a PUT request on the {{ name }} resource">PUT</button>
|
||||
<button class="btn btn-primary js-tooltip" title="{% blocktrans %}Make a PUT request on the {{ name }} resource{% endblocktrans %}">PUT</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
@ -227,10 +227,10 @@
|
||||
{% include "rest_framework/raw_data_form.html" %}
|
||||
<div class="form-actions">
|
||||
{% if raw_data_put_form %}
|
||||
<button class="btn btn-primary js-tooltip" title="Make a PUT request on the {{ name }} resource">PUT</button>
|
||||
<button class="btn btn-primary js-tooltip" title="{% blocktrans %}Make a PUT request on the {{ name }} resource{% endblocktrans %}">PUT</button>
|
||||
{% endif %}
|
||||
{% if raw_data_patch_form %}
|
||||
<button data-method="PATCH" class="btn btn-primary js-tooltip" title="Make a PATCH request on the {{ name }} resource">PATCH</button>
|
||||
<button data-method="PATCH" class="btn btn-primary js-tooltip" title="{% blocktrans %}Make a PATCH request on the {{ name }} resource{% endblocktrans %}">PATCH</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
{% load i18n %}
|
||||
<html lang="en" ng-app="Tower">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Ansible Tower</title>
|
||||
<title>{% trans 'Ansible Tower' %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="{{ STATIC_URL }}assets/custom-theme/jquery-ui-1.10.3.custom.min.css" />
|
||||
<link rel="stylesheet" href="{{ STATIC_URL }}assets/ansible-bootstrap.min.css" />
|
||||
@ -49,7 +50,7 @@
|
||||
|
||||
<!-- Password Dialog -->
|
||||
<div id="password-modal" style="display: none;"></div>
|
||||
<div id="idle-modal" style="display:none">Your session will expire in <span id="remaining_seconds" class="IdleModal-remainingSeconds">60</span> seconds, would you like to continue?</div>
|
||||
<div id="idle-modal" style="display:none">{% blocktrans %}Your session will expire in <span id="remaining_seconds" class="IdleModal-remainingSeconds">60</span> seconds, would you like to continue?{% endblocktrans %}</div>
|
||||
|
||||
<stream-detail-modal></stream-detail-modal>
|
||||
|
||||
@ -155,27 +156,27 @@
|
||||
|
||||
<div id="prompt-for-days" style="display:none">
|
||||
<form name="prompt_for_days_form" id="prompt_for_days_form" class="MgmtCards-promptText">
|
||||
Set how many days of data should be retained. <br>
|
||||
{% trans 'Set how many days of data should be retained.' %}<br>
|
||||
<input type="integer" id="days_to_keep" name="days_to_keep" ng-model="days_to_keep" ng-required="true" class="form-control Form-textInput" min=0 max=9999 style="margin-top:10px;" integer>
|
||||
<div class="error" ng-show="prompt_for_days_form.days_to_keep.$dirty && (prompt_for_days_form.days_to_keep.$error.number || prompt_for_days_form.days_to_keep.$error.integer ||
|
||||
prompt_for_days_form.days_to_keep.$error.required ||
|
||||
prompt_for_days_form.days_to_keep.$error.min ||
|
||||
prompt_for_days_form.days_to_keep.$error.max)">Please enter an integer<span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.min"> that is not negative</span><span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.max"> that is lower than 9999</span>.</div>
|
||||
prompt_for_days_form.days_to_keep.$error.max)">{% blocktrans %}Please enter an integer<span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.min"> that is not negative</span><span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.max"> that is lower than 9999</span>.{% endblocktrans %}</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="prompt-for-days-facts" style="display:none">
|
||||
<form name="prompt_for_days_facts_form" id="prompt_for_days_facts_form" class="MgmtCards-promptText">
|
||||
<div style="padding-bottom:15px;">For facts collected older than the time period specified,
|
||||
<div style="padding-bottom:15px;">{% blocktrans %}For facts collected older than the time period specified,
|
||||
save one fact scan (snapshot) per time window (frequency).
|
||||
For example, facts older than 30 days are purged, while one
|
||||
weekly fact scan is kept.<br> <br>
|
||||
|
||||
CAUTION: Setting both numerical variables to "0" will delete all facts.<br><br>
|
||||
CAUTION: Setting both numerical variables to "0" will delete all facts.<br><br>{% endblocktrans %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">
|
||||
<span class="label-text">
|
||||
Select a time period after which to remove old facts
|
||||
{% trans 'Select a time period after which to remove old facts' %}
|
||||
</span>
|
||||
</label>
|
||||
<div class="row">
|
||||
@ -189,12 +190,12 @@
|
||||
<div class="error" ng-show="prompt_for_days_facts_form.keep_amount.$dirty && (prompt_for_days_facts_form.keep_amount.$error.number || prompt_for_days_facts_form.keep_amount.$error.integer ||
|
||||
prompt_for_days_facts_form.keep_amount.$error.required ||
|
||||
prompt_for_days_facts_form.keep_amount.$error.min ||
|
||||
prompt_for_days_facts_form.keep_amount.$error.max)">Please enter an integer<span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.max"> that is lower than 9999</span>.</div>
|
||||
prompt_for_days_facts_form.keep_amount.$error.max)">{% blocktrans %}Please enter an integer<span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.max"> that is lower than 9999</span>.{% endblocktrans %}</div>
|
||||
</div>
|
||||
<div class="form-group ">
|
||||
<label for="description">
|
||||
<span class="label-text">
|
||||
Select a frequency for snapshot retention
|
||||
{% trans 'Select a frequency for snapshot retention' %}
|
||||
</span>
|
||||
</label>
|
||||
<div class="row">
|
||||
@ -209,14 +210,14 @@
|
||||
<div class="error" ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && (prompt_for_days_facts_form.granularity_keep_amount.$error.number || prompt_for_days_facts_form.granularity_keep_amount.$error.integer ||
|
||||
prompt_for_days_facts_form.granularity_keep_amount.$error.required ||
|
||||
prompt_for_days_facts_form.granularity_keep_amount.$error.min ||
|
||||
prompt_for_days_facts_form.granularity_keep_amount.$error.max)">Please enter an integer<span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.max"> that is lower than 9999</span>.</div>
|
||||
prompt_for_days_facts_form.granularity_keep_amount.$error.max)">{% blocktrans %}Please enter an integer<span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.max"> that is lower than 9999</span>.{% endblocktrans %}</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="overlay"></div>
|
||||
<div class="spinny"><i class="fa fa-cog fa-spin fa-2x"></i> <p>working...</p></div>
|
||||
<div class="spinny"><i class="fa fa-cog fa-spin fa-2x"></i> <p>{% trans 'working...' %}</p></div>
|
||||
</div>
|
||||
<tower-footer></tower-footer>
|
||||
</body>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user