Added dynamic help text to backend route
This commit is contained in:
parent
2eb2fb5a5c
commit
d422e109e9
13
TODO.md
13
TODO.md
|
@ -200,3 +200,16 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
* User [Group] webapp/website option (validation) which overrides default mainsystemuser
|
||||
|
||||
* validate systemuser.home
|
||||
|
||||
* Create plugin app
|
||||
|
||||
* Create options widget
|
||||
|
||||
* generic options fpm/fcgid/uwsgi webapps (num procs, idle io timeout)
|
||||
* webapp backend option compatibility check?
|
||||
|
||||
|
||||
* Route help text with model name when selecting backend
|
||||
* Service instance name when selecting content_type
|
||||
|
||||
* Address.forward mailbbox validate not available on mailboxes
|
||||
|
|
|
@ -203,10 +203,11 @@ class SelectPluginAdminMixin(object):
|
|||
""" Redirects to select account view if required """
|
||||
if request.user.is_superuser:
|
||||
plugin_value = request.GET.get(self.plugin_field) or request.POST.get(self.plugin_field)
|
||||
if plugin_value or self.plugin.get_plugins() == 1:
|
||||
if plugin_value or len(self.plugin.get_plugins()) == 1:
|
||||
self.plugin_value = plugin_value
|
||||
if not plugin_value:
|
||||
self.plugin_value = self.plugin.get_plugins()[0]
|
||||
self.plugin_value = self.plugin.get_plugins()[0].get_plugin_name()
|
||||
b = self.plugin_value
|
||||
context = {
|
||||
'title': _("Add new %s") % camel_case_to_spaces(self.plugin_value),
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ from functools import wraps
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.shortcuts import redirect
|
||||
|
@ -99,7 +100,10 @@ def admin_link(*args, **kwargs):
|
|||
if kwargs['field'] in ['id', 'pk', '__unicode__']:
|
||||
obj = instance
|
||||
else:
|
||||
obj = get_field_value(instance, kwargs['field'])
|
||||
try:
|
||||
obj = get_field_value(instance, kwargs['field'])
|
||||
except ObjectDoesNotExist:
|
||||
return '---'
|
||||
if not getattr(obj, 'pk', None):
|
||||
return '---'
|
||||
url = change_url(obj)
|
||||
|
|
|
@ -20,13 +20,12 @@ class BillContact(models.Model):
|
|||
account = models.OneToOneField('accounts.Account', verbose_name=_("account"),
|
||||
related_name='billcontact')
|
||||
name = models.CharField(_("name"), max_length=256, blank=True,
|
||||
help_text=_("Account full name will be used when not provided"))
|
||||
help_text=_("Account full name will be used when left blank."))
|
||||
address = models.TextField(_("address"))
|
||||
city = models.CharField(_("city"), max_length=128,
|
||||
default=settings.BILLS_CONTACT_DEFAULT_CITY)
|
||||
zipcode = models.CharField(_("zip code"), max_length=10,
|
||||
validators=[RegexValidator(r'^[0-9A-Z]{3,10}$',
|
||||
_("Enter a valid zipcode."), 'invalid')])
|
||||
validators=[RegexValidator(r'^[0-9A-Z]{3,10}$', _("Enter a valid zipcode."))])
|
||||
country = models.CharField(_("country"), max_length=20,
|
||||
choices=settings.BILLS_CONTACT_COUNTRIES,
|
||||
default=settings.BILLS_CONTACT_DEFAULT_COUNTRY)
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.utils.html import escape
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||
from orchestra.admin.html import monospace_format
|
||||
from orchestra.admin.utils import admin_link, admin_date, admin_colored
|
||||
|
||||
from .backends import ServiceBackend
|
||||
from .models import Server, Route, BackendLog, BackendOperation
|
||||
|
||||
|
||||
|
@ -27,6 +30,11 @@ class RouteAdmin(admin.ModelAdmin):
|
|||
list_editable = ['backend', 'host', 'match', 'is_active']
|
||||
list_filter = ['host', 'is_active', 'backend']
|
||||
|
||||
BACKEND_HELP_TEXT = {
|
||||
backend: "This backend operates over '%s'" % ServiceBackend.get_backend(backend).model
|
||||
for backend, __ in ServiceBackend.get_plugin_choices()
|
||||
}
|
||||
|
||||
def display_model(self, route):
|
||||
try:
|
||||
return escape(route.backend_class().model)
|
||||
|
@ -43,6 +51,19 @@ class RouteAdmin(admin.ModelAdmin):
|
|||
display_actions.short_description = _("actions")
|
||||
display_actions.allow_tags = True
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Provides dynamic help text on backend form field """
|
||||
if db_field.name == 'backend':
|
||||
kwargs['widget'] = DynamicHelpTextSelect('this.id', self.BACKEND_HELP_TEXT)
|
||||
return super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
""" Include dynamic help text for existing objects """
|
||||
form = super(RouteAdmin, self).get_form(request, obj=obj, **kwargs)
|
||||
if obj:
|
||||
form.base_fields['backend'].help_text = self.BACKEND_HELP_TEXT[obj.backend]
|
||||
return form
|
||||
|
||||
|
||||
class BackendOperationInline(admin.TabularInline):
|
||||
model = BackendOperation
|
||||
|
|
|
@ -6,6 +6,7 @@ from django.utils.translation import ugettext, ugettext_lazy as _
|
|||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.utils import change_url
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||
|
||||
from . import settings
|
||||
from .models import WebApp, WebAppOption
|
||||
|
@ -26,21 +27,13 @@ class WebAppOptionInline(admin.TabularInline):
|
|||
}
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Make value input widget bigger """
|
||||
if db_field.name == 'value':
|
||||
kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
|
||||
if db_field.name == 'name':
|
||||
# Help text based on select widget
|
||||
kwargs['widget'] = forms.Select(attrs={
|
||||
'onChange': """
|
||||
siteoptions = %s;
|
||||
valueelement = $("#"+this.id.replace("name", "value"));
|
||||
valueelement.parent().find('p').remove();
|
||||
valueelement.parent().append(
|
||||
"<p class='help'>" + siteoptions[this.options[this.selectedIndex].value] + "</p>"
|
||||
);
|
||||
""" % str(self.OPTIONS_HELP_TEXT),
|
||||
})
|
||||
kwargs['widget'] = DynamicHelpTextSelect(
|
||||
'this.id.replace("name", "value")', self.OPTIONS_HELP_TEXT
|
||||
)
|
||||
return super(WebAppOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
|
||||
|
@ -67,7 +60,7 @@ class WebAppAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
name = "%s on %s" % (website.name, content.path)
|
||||
websites.append('<a href="%s">%s</a>' % (url, name))
|
||||
add_url = reverse('admin:websites_website_add')
|
||||
# TODO support for preselecting related we app on website
|
||||
# TODO support for preselecting related web app on website
|
||||
add_url += '?account=%s' % webapp.account_id
|
||||
plus = '<strong style="color:green; font-size:12px">+</strong>'
|
||||
websites.append('<a href="%s">%s%s</a>' % (add_url, plus, ugettext("Add website")))
|
||||
|
@ -80,7 +73,7 @@ class WebAppAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
if db_field.name == 'type':
|
||||
# Help text based on select widget
|
||||
kwargs['widget'] = forms.Select(attrs={
|
||||
'onChange': """
|
||||
'onClick': """
|
||||
siteoptions = %s;
|
||||
valueelement = $("#"+this.id);
|
||||
valueelement.parent().find('p').remove();
|
||||
|
|
|
@ -29,20 +29,20 @@ WEBAPPS_FCGID_PATH = getattr(settings, 'WEBAPPS_FCGID_PATH',
|
|||
|
||||
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', {
|
||||
'php5.5': {
|
||||
'verbose_name': "PHP 5.5",
|
||||
'verbose_name': "PHP 5.5 fpm",
|
||||
# 'fpm', ('unix:/var/run/%(user)s-%(app_name)s.sock|fcgi://127.0.0.1%(app_path)s',),
|
||||
'directive': ('fpm', 'fcgi://{}%(app_path)s'.format(WEBAPPS_FPM_LISTEN)),
|
||||
'help_text': _("This creates a PHP5.5 application under ~/webapps/<app_name><br>"
|
||||
"PHP-FPM will be used to execute PHP files.")
|
||||
},
|
||||
'php5.2': {
|
||||
'verbose_name': "PHP 5.2",
|
||||
'verbose_name': "PHP 5.2 fcgi",
|
||||
'directive': ('fcgi', WEBAPPS_FCGID_PATH),
|
||||
'help_text': _("This creates a PHP5.2 application under ~/webapps/<app_name><br>"
|
||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||
},
|
||||
'php4': {
|
||||
'verbose_name': "PHP 4",
|
||||
'verbose_name': "PHP 4 fcgi",
|
||||
'directive': ('fcgi', WEBAPPS_FCGID_PATH,),
|
||||
'help_text': _("This creates a PHP4 application under ~/webapps/<app_name><br>"
|
||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||
|
@ -104,8 +104,24 @@ WEBAPPS_PHP_DISABLED_FUNCTIONS = getattr(settings, 'WEBAPPS_PHP_DISABLED_FUNCTIO
|
|||
|
||||
WEBAPPS_OPTIONS = getattr(settings, 'WEBAPPS_OPTIONS', {
|
||||
# { name: ( verbose_name, [help_text], validation_regex ) }
|
||||
# Processes
|
||||
'timeout': (
|
||||
_("Process timeout"),
|
||||
_("Maximum time in seconds allowed for a request to complete (a number between 0 and 999)."),
|
||||
# FCGID FcgidIOTimeout
|
||||
# FPM pm.request_terminate_timeout
|
||||
# PHP max_execution_time ini
|
||||
r'^[0-9]{1,3}$',
|
||||
),
|
||||
'processes': (
|
||||
_("Number of processes"),
|
||||
_("Maximum number of children that can be alive at the same time (a number between 0 and 9)."),
|
||||
# FCGID MaxProcesses
|
||||
# FPM pm.max_children
|
||||
r'^[0-9]$',
|
||||
),
|
||||
# PHP
|
||||
'enabled_functions': (
|
||||
'php-enabled_functions': (
|
||||
_("PHP - Enabled functions"),
|
||||
' '.join(WEBAPPS_PHP_DISABLED_FUNCTIONS),
|
||||
r'^[\w\.,-]+$'
|
||||
|
@ -249,30 +265,4 @@ WEBAPPS_OPTIONS = getattr(settings, 'WEBAPPS_OPTIONS', {
|
|||
_("PHP - zend_extension"),
|
||||
r'^[^ ]+$'
|
||||
),
|
||||
# FCGID
|
||||
'FcgidIdleTimeout': (
|
||||
_("FCGI - Idle timeout"),
|
||||
_("Number between 0 and 999."),
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'FcgidBusyTimeout': (
|
||||
_("FCGI - Busy timeout"),
|
||||
_("Number between 0 and 999."),
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'FcgidConnectTimeout': (
|
||||
_("FCGI - Connection timeout"),
|
||||
_("Number of seconds between 0 and 999."),
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'FcgidIOTimeout': (
|
||||
_("FCGI - IO timeout"),
|
||||
_("Number of seconds between 0 and 999."),
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'FcgidProcessLifeTime': (
|
||||
_("FCGI - IO timeout"),
|
||||
_("Numbe of secondsr between 0 and 9999."),
|
||||
r'^[0-9]{1,4}$'
|
||||
),
|
||||
})
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.utils import admin_link, change_url
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||
|
||||
from . import settings
|
||||
from .models import Content, Website, WebsiteOption
|
||||
|
@ -25,21 +26,13 @@ class WebsiteOptionInline(admin.TabularInline):
|
|||
# }
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Make value input widget bigger """
|
||||
if db_field.name == 'value':
|
||||
kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
|
||||
if db_field.name == 'name':
|
||||
# Help text based on select widget
|
||||
kwargs['widget'] = forms.Select(attrs={
|
||||
'onChange': """
|
||||
siteoptions = %s;
|
||||
valueelement = $("#"+this.id.replace("name", "value"));
|
||||
valueelement.parent().find('p').remove();
|
||||
valueelement.parent().append(
|
||||
"<p class='help'>" + siteoptions[this.options[this.selectedIndex].value] + "</p>"
|
||||
);
|
||||
""" % str(self.OPTIONS_HELP_TEXT),
|
||||
})
|
||||
kwargs['widget'] = DynamicHelpTextSelect(
|
||||
'this.id.replace("name", "value")', self.OPTIONS_HELP_TEXT
|
||||
)
|
||||
return super(WebsiteOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import re
|
||||
import textwrap
|
||||
|
||||
from django import forms
|
||||
from django.utils.safestring import mark_safe
|
||||
|
@ -63,3 +64,25 @@ def paddingCheckboxSelectMultiple(padding):
|
|||
return mark_safe(value)
|
||||
widget.render = render
|
||||
return widget
|
||||
|
||||
|
||||
class DynamicHelpTextSelect(forms.Select):
|
||||
def __init__(self, target, help_text, *args, **kwargs):
|
||||
help_text = self.get_dynamic_help_text(target, help_text)
|
||||
attrs = {
|
||||
'onClick': help_text,
|
||||
'onChange': help_text,
|
||||
}
|
||||
attrs.update(kwargs.get('attrs', {}))
|
||||
kwargs['attrs'] = attrs
|
||||
super(DynamicHelpTextSelect, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_dynamic_help_text(self, target, help_text):
|
||||
return textwrap.dedent("""\
|
||||
siteoptions = {help_text};
|
||||
valueelement = $("#" + {target});
|
||||
valueelement.parent().find('p').remove();
|
||||
valueelement.parent().append(
|
||||
"<p class='help'>" + siteoptions[this.options[this.selectedIndex].value] + "</p>"
|
||||
);""".format(target=target, help_text=str(help_text))
|
||||
)
|
||||
|
|
|
@ -56,6 +56,6 @@ def dict_setting_to_choices(choices):
|
|||
|
||||
def tuple_setting_to_choices(choices):
|
||||
return sorted(
|
||||
[ (name, opt[0]) for name,opt in choices.iteritems() ],
|
||||
tuple((name, opt[0]) for name, opt in choices.iteritems()),
|
||||
key=lambda e: e[0]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue