Improved misc admin interface
This commit is contained in:
parent
202d1fd632
commit
fed13217dc
10
README.md
10
README.md
|
@ -71,16 +71,16 @@ Quick Start
|
||||||
```bash
|
```bash
|
||||||
orchestra@panel:~ ssh-copy-id root@server.address
|
orchestra@panel:~ ssh-copy-id root@server.address
|
||||||
```
|
```
|
||||||
Then add the servers using the web interface `/admin/orchestration/servers`, check that the SSH connection is working and Orchestra can report the uptime of the servers.
|
Then add the servers using the web interface `/admin/orchestration/servers`, check that the SSH connection is working and Orchestra is able to report servers uptimes.
|
||||||
|
|
||||||
2. Configure the services, one at a time, staring with domains, databases, webapps, websites, ...
|
2. Configure your services, one at a time, staring with domains, databases, webapps, websites, ...
|
||||||
1. Add related [routes](orchestra/contrib/orchestration) via `/admin/orchestration/route/`
|
1. Add related [routes](orchestra/contrib/orchestration) via `/admin/orchestration/route/`
|
||||||
2. Configure related settings on `/admin/settings/setting/`
|
2. Configure related settings on `/admin/settings/setting/`
|
||||||
3. If required, configure related [resources](orchestra/contrib/resources) like Account disc limit, VPS traffic, etc `/resources/resource/`
|
3. If required, configure related [resources](orchestra/contrib/resources) like *account disk limit*, *VPS traffic*, etc `/resources/resource/`
|
||||||
3. Test creating and deleting service instances works as expected
|
3. Test if create and delete service instances works as expected
|
||||||
4. Do the same for the remaining services. You can disable services that you don't want by editing `INSTALLED_APPS` setting
|
4. Do the same for the remaining services. You can disable services that you don't want by editing `INSTALLED_APPS` setting
|
||||||
|
|
||||||
3. Configure billing by adding [services](orchestra/contrib/services) `/admin/services/service/add/` and [plans](orchestra/contrib/plans) `/admin/plans/plan/`. Once a service is created hit the *Update orders* button to create orders for existing service instances.
|
3. Configure billing by adding [services](orchestra/contrib/services) `/admin/services/service/add/` and [plans](orchestra/contrib/plans) `/admin/plans/plan/`. Once a service is created hit the *Update orders* button to create orders for existing service instances, orders for new instances will be automatically created.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
6
TODO.md
6
TODO.md
|
@ -454,3 +454,9 @@ mkhomedir_helper or create ssh homes with bash.rc and such
|
||||||
# exclude from change list action, support for multiple exclusion
|
# exclude from change list action, support for multiple exclusion
|
||||||
|
|
||||||
# breadcrumbs https://orchestra.pangea.org/admin/domains/domain/?account_id=930
|
# breadcrumbs https://orchestra.pangea.org/admin/domains/domain/?account_id=930
|
||||||
|
|
||||||
|
with open(file) as handler:
|
||||||
|
os.unlink(file)
|
||||||
|
|
||||||
|
|
||||||
|
# change filter By PHP version: by detail
|
||||||
|
|
|
@ -21,6 +21,7 @@ from .models import MiscService, Miscellaneous
|
||||||
class MiscServicePlugin(PluginModelAdapter):
|
class MiscServicePlugin(PluginModelAdapter):
|
||||||
model = MiscService
|
model = MiscService
|
||||||
name_field = 'name'
|
name_field = 'name'
|
||||||
|
plugin_field = 'service'
|
||||||
|
|
||||||
|
|
||||||
class MiscServiceAdmin(ExtendedModelAdmin):
|
class MiscServiceAdmin(ExtendedModelAdmin):
|
||||||
|
@ -56,12 +57,16 @@ class MiscServiceAdmin(ExtendedModelAdmin):
|
||||||
return super(MiscServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(MiscServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelAdmin):
|
class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'__str__', 'service_link', 'amount', 'account_link', 'dispaly_active'
|
'__str__', 'service_link', 'amount', 'account_link', 'dispaly_active'
|
||||||
)
|
)
|
||||||
list_filter = ('service__name', 'is_active')
|
list_filter = ('service__name', 'is_active')
|
||||||
list_select_related = ('service', 'account')
|
list_select_related = ('service', 'account')
|
||||||
|
readonly_fields = ('account_link', 'service_link')
|
||||||
|
add_fields = ('service', 'account', 'description', 'is_active')
|
||||||
|
fields = ('service_link', 'account', 'description', 'is_active')
|
||||||
|
change_readonly_fields = ('identifier', 'service')
|
||||||
search_fields = ('identifier', 'description', 'account__username')
|
search_fields = ('identifier', 'description', 'account__username')
|
||||||
actions = (disable, enable)
|
actions = (disable, enable)
|
||||||
plugin_field = 'service'
|
plugin_field = 'service'
|
||||||
|
@ -82,19 +87,26 @@ class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelA
|
||||||
return obj.service
|
return obj.service
|
||||||
|
|
||||||
def get_fields(self, request, obj=None):
|
def get_fields(self, request, obj=None):
|
||||||
fields = ['account', 'description', 'is_active']
|
fields = super().get_fields(request, obj)
|
||||||
if obj is not None:
|
fields = list(fields)
|
||||||
fields = ['account_link', 'description', 'is_active']
|
|
||||||
service = self.get_service(obj)
|
service = self.get_service(obj)
|
||||||
|
if obj:
|
||||||
|
fields.insert(1, 'account_link')
|
||||||
if service.has_amount:
|
if service.has_amount:
|
||||||
fields.insert(-1, 'amount')
|
fields.insert(-1, 'amount')
|
||||||
if service.has_identifier:
|
if service.has_identifier:
|
||||||
fields.insert(1, 'identifier')
|
fields.insert(2, 'identifier')
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
form = super(SelectPluginAdminMixin, self).get_form(request, obj, **kwargs)
|
if obj:
|
||||||
|
plugin = self.plugin.get(obj.service.name)()
|
||||||
|
else:
|
||||||
|
plugin = self.plugin.get(self.plugin_value)()
|
||||||
|
self.form = plugin.get_form()
|
||||||
|
self.plugin_instance = plugin
|
||||||
service = self.get_service(obj)
|
service = self.get_service(obj)
|
||||||
|
form = super(SelectPluginAdminMixin, self).get_form(request, obj, **kwargs)
|
||||||
def clean_identifier(self, service=service):
|
def clean_identifier(self, service=service):
|
||||||
identifier = self.cleaned_data['identifier']
|
identifier = self.cleaned_data['identifier']
|
||||||
validator_path = settings.MISCELLANEOUS_IDENTIFIER_VALIDATORS.get(service.name, None)
|
validator_path = settings.MISCELLANEOUS_IDENTIFIER_VALIDATORS.get(service.name, None)
|
||||||
|
|
|
@ -55,7 +55,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
)
|
)
|
||||||
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
|
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link', )
|
readonly_fields = ('account_link',)
|
||||||
change_readonly_fields = ('name', 'type', 'display_websites')
|
change_readonly_fields = ('name', 'type', 'display_websites')
|
||||||
search_fields = ('name', 'account__username', 'data', 'website__domains__name')
|
search_fields = ('name', 'account__username', 'data', 'website__domains__name')
|
||||||
list_prefetch_related = ('content_set__website', 'content_set__website__domains')
|
list_prefetch_related = ('content_set__website', 'content_set__website__domains')
|
||||||
|
|
|
@ -1,20 +1,26 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
|
from orchestra.admin.utils import admin_link
|
||||||
from orchestra.forms.widgets import SpanWidget
|
from orchestra.forms.widgets import SpanWidget
|
||||||
|
|
||||||
|
|
||||||
class PluginDataForm(forms.ModelForm):
|
class PluginForm(forms.ModelForm):
|
||||||
data = forms.CharField(widget=forms.HiddenInput, required=False)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PluginDataForm, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if self.plugin_field in self.fields:
|
if self.plugin_field in self.fields:
|
||||||
value = self.plugin.get_name()
|
value = self.plugin.get_name()
|
||||||
display = '%s <a href=".">change</a>' % force_text(self.plugin.verbose_name)
|
display = '%s <a href=".">change</a>' % force_text(self.plugin.verbose_name)
|
||||||
self.fields[self.plugin_field].widget = SpanWidget(original=value, display=display)
|
self.fields[self.plugin_field].widget = SpanWidget(original=value, display=display)
|
||||||
help_text = self.fields[self.plugin_field].help_text
|
help_text = self.fields[self.plugin_field].help_text
|
||||||
self.fields[self.plugin_field].help_text = getattr(self.plugin, 'help_text', help_text)
|
self.fields[self.plugin_field].help_text = getattr(self.plugin, 'help_text', help_text)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginDataForm(PluginForm):
|
||||||
|
data = forms.CharField(widget=forms.HiddenInput, required=False)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
if self.instance:
|
if self.instance:
|
||||||
for field in self.declared_fields:
|
for field in self.declared_fields:
|
||||||
initial = self.fields[field].initial
|
initial = self.fields[field].initial
|
||||||
|
@ -37,7 +43,7 @@ class PluginDataForm(forms.ModelForm):
|
||||||
self.fields[field].widget = SpanWidget(original=value, display=display)
|
self.fields[field].widget = SpanWidget(original=value, display=display)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super(PluginDataForm, self).clean()
|
super().clean()
|
||||||
data = {}
|
data = {}
|
||||||
# Update data fields
|
# Update data fields
|
||||||
for field in self.declared_fields:
|
for field in self.declared_fields:
|
||||||
|
@ -53,3 +59,15 @@ class PluginDataForm(forms.ModelForm):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
data[field] = value
|
data[field] = value
|
||||||
self.cleaned_data['data'] = data
|
self.cleaned_data['data'] = data
|
||||||
|
|
||||||
|
|
||||||
|
class PluginModelAdapterForm(PluginForm):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(PluginForm, self).__init__(*args, **kwargs)
|
||||||
|
if self.plugin_field in self.fields:
|
||||||
|
# Provide a link to the related DB object change view
|
||||||
|
value = self.plugin.related_instance.pk
|
||||||
|
link = admin_link()(self.plugin.related_instance)
|
||||||
|
display = '%s <a href=".">change</a>' % link
|
||||||
|
self.fields[self.plugin_field].widget = SpanWidget(original=value, display=display)
|
||||||
|
help_text = self.fields[self.plugin_field].help_text
|
||||||
|
|
|
@ -15,6 +15,8 @@ class Plugin(object):
|
||||||
def __init__(self, instance=None):
|
def __init__(self, instance=None):
|
||||||
# Related model instance of this plugin
|
# Related model instance of this plugin
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
|
from .forms import PluginForm
|
||||||
|
self.form = PluginForm
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_name(cls):
|
def get_name(cls):
|
||||||
|
@ -92,6 +94,11 @@ class PluginModelAdapter(Plugin):
|
||||||
model = None
|
model = None
|
||||||
name_field = None
|
name_field = None
|
||||||
|
|
||||||
|
def __init__(self, instance=None):
|
||||||
|
super().__init__(instance)
|
||||||
|
from .forms import PluginModelAdapterForm
|
||||||
|
self.form = PluginModelAdapterForm
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_plugins(cls):
|
def get_plugins(cls):
|
||||||
plugins = []
|
plugins = []
|
||||||
|
|
Loading…
Reference in New Issue