diff --git a/tailbone/views/tempmon/__init__.py b/tailbone/views/tempmon/__init__.py index 81e94211..5f26a065 100644 --- a/tailbone/views/tempmon/__init__.py +++ b/tailbone/views/tempmon/__init__.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8; -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2017 Lance Edgar +# Copyright © 2010-2018 Lance Edgar # # This file is part of Rattail. # @@ -26,7 +26,7 @@ Views for tempmon from __future__ import unicode_literals, absolute_import -from .core import MasterView, ClientFieldRenderer, ProbeFieldRenderer +from .core import MasterView def includeme(config): diff --git a/tailbone/views/tempmon/clients.py b/tailbone/views/tempmon/clients.py index d1b9db65..ef6d453a 100644 --- a/tailbone/views/tempmon/clients.py +++ b/tailbone/views/tempmon/clients.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2017 Lance Edgar +# Copyright © 2010-2018 Lance Edgar # # This file is part of Rattail. # @@ -28,37 +28,16 @@ from __future__ import unicode_literals, absolute_import import subprocess +import six + from rattail_tempmon.db import model as tempmon -import formalchemy as fa +import colander from webhelpers2.html import HTML, tags -from tailbone.db import TempmonSession from tailbone.views.tempmon import MasterView -class ProbesFieldRenderer(fa.FieldRenderer): - - def render_readonly(self, **kwargs): - probes = self.raw_value - if not probes: - return '' - items = [] - for probe in probes: - items.append(HTML.tag('li', c=tags.link_to(probe, self.request.route_url('tempmon.probes.view', uuid=probe.uuid)))) - return HTML.tag('ul', c=items) - - -def unique_config_key(value, field): - client = field.parent.model - query = TempmonSession.query(tempmon.Client)\ - .filter(tempmon.Client.config_key == value) - if client.uuid: - query = query.filter(tempmon.Client.uuid != client.uuid) - if query.count(): - raise fa.ValidationError("Config key must be unique") - - class TempmonClientView(MasterView): """ Master view for tempmon clients. @@ -78,6 +57,16 @@ class TempmonClientView(MasterView): 'online', ] + form_fields = [ + 'config_key', + 'hostname', + 'location', + 'delay', + 'probes', + 'enabled', + 'online', + ] + def configure_grid(self, g): super(TempmonClientView, self).configure_grid(g) g.filters['hostname'].default_active = True @@ -95,24 +84,38 @@ class TempmonClientView(MasterView): g.set_link('hostname') g.set_link('location') - def _preconfigure_fieldset(self, fs): - fs.config_key.set(validate=unique_config_key) - fs.probes.set(renderer=ProbesFieldRenderer) + def configure_form(self, f): + super(TempmonClientView, self).configure_form(f) + + # config_key + f.set_validator('config_key', self.unique_config_key) + + # probes + f.set_renderer('probes', self.render_probes) - def configure_fieldset(self, fs): - fs.configure( - include=[ - fs.config_key, - fs.hostname, - fs.location, - fs.delay, - fs.probes, - fs.enabled, - fs.online, - ]) if self.creating or self.editing: - del fs.probes - del fs.online + f.remove_fields('probes', + 'online') + + def unique_config_key(self, node, value): + query = self.Session.query(tempmon.Client)\ + .filter(tempmon.Client.config_key == value) + if self.editing: + client = self.get_instance() + query = query.filter(tempmon.Client.uuid != client.uuid) + if query.count(): + raise colander.Invalid(node, "Config key must be unique") + + def render_probes(self, client, field): + probes = client.probes + if not probes: + return "" + items = [] + for probe in probes: + text = six.text_type(probe) + url = self.request.route_url('tempmon.probes.view', uuid=probe.uuid) + items.append(HTML.tag('li', c=tags.link_to(text, url))) + return HTML.tag('ul', c=items) def delete_instance(self, client): # bulk-delete all readings first diff --git a/tailbone/views/tempmon/core.py b/tailbone/views/tempmon/core.py index 545eb3cb..f32c596a 100644 --- a/tailbone/views/tempmon/core.py +++ b/tailbone/views/tempmon/core.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2017 Lance Edgar +# Copyright © 2010-2018 Lance Edgar # # This file is part of Rattail. # @@ -28,14 +28,11 @@ from __future__ import unicode_literals, absolute_import from rattail_tempmon.db import Session as RawTempmonSession -from formalchemy.fields import SelectFieldRenderer -from webhelpers2.html import tags - from tailbone import views from tailbone.db import TempmonSession -class MasterView(views.MasterView2): +class MasterView(views.MasterView3): """ Base class for tempmon views. """ @@ -43,21 +40,3 @@ class MasterView(views.MasterView2): def get_bulk_delete_session(self): return RawTempmonSession() - - -class ClientFieldRenderer(SelectFieldRenderer): - - def render_readonly(self, **kwargs): - client = self.raw_value - if not client: - return '' - return tags.link_to(client, self.request.route_url('tempmon.clients.view', uuid=client.uuid)) - - -class ProbeFieldRenderer(SelectFieldRenderer): - - def render_readonly(self, **kwargs): - probe = self.raw_value - if not probe: - return '' - return tags.link_to(probe, self.request.route_url('tempmon.probes.view', uuid=probe.uuid)) diff --git a/tailbone/views/tempmon/probes.py b/tailbone/views/tempmon/probes.py index b55e9e65..8043759d 100644 --- a/tailbone/views/tempmon/probes.py +++ b/tailbone/views/tempmon/probes.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2017 Lance Edgar +# Copyright © 2010-2018 Lance Edgar # # This file is part of Rattail. # @@ -26,23 +26,15 @@ Views for tempmon probes from __future__ import unicode_literals, absolute_import +import six + from rattail_tempmon.db import model as tempmon -import formalchemy as fa +import colander +from webhelpers2.html import tags from tailbone import forms -from tailbone.db import TempmonSession -from tailbone.views.tempmon import MasterView, ClientFieldRenderer - - -def unique_config_key(value, field): - probe = field.parent.model - query = TempmonSession.query(tempmon.Probe)\ - .filter(tempmon.Probe.config_key == value) - if probe.uuid: - query = query.filter(tempmon.Probe.uuid != probe.uuid) - if query.count(): - raise fa.ValidationError("Config key must be unique") +from tailbone.views.tempmon import MasterView class TempmonProbeView(MasterView): @@ -65,6 +57,22 @@ class TempmonProbeView(MasterView): 'status', ] + form_fields = [ + 'client', + 'config_key', + 'appliance_type', + 'description', + 'device_path', + 'critical_temp_min', + 'good_temp_min', + 'good_temp_max', + 'critical_temp_max', + 'therm_status_timeout', + 'status_alert_timeout', + 'enabled', + 'status', + ] + def configure_grid(self, g): super(TempmonProbeView, self).configure_grid(g) @@ -83,31 +91,40 @@ class TempmonProbeView(MasterView): g.set_link('config_key') g.set_link('description') - def _preconfigure_fieldset(self, fs): - fs.config_key.set(validate=unique_config_key) - fs.client.set(label="TempMon Client", renderer=ClientFieldRenderer) - fs.appliance_type.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.TEMPMON_APPLIANCE_TYPE)) - fs.status.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.TEMPMON_PROBE_STATUS)) + def configure_form(self, f): + super(TempmonProbeView, self).configure_form(f) - def configure_fieldset(self, fs): - fs.configure( - include=[ - fs.client, - fs.config_key, - fs.appliance_type, - fs.description, - fs.device_path, - fs.critical_temp_min, - fs.good_temp_min, - fs.good_temp_max, - fs.critical_temp_max, - fs.therm_status_timeout, - fs.status_alert_timeout, - fs.enabled, - fs.status, - ]) + # config_key + f.set_validator('config_key', self.unique_config_key) + + # client + f.set_renderer('client', self.render_client) + f.set_label('client', "Tempmon Client") + + # appliance_type + f.set_enum('appliance_type', self.enum.TEMPMON_APPLIANCE_TYPE) + + # status + f.set_enum('status', self.enum.TEMPMON_PROBE_STATUS) if self.creating or self.editing: - del fs.status + f.remove_fields('status') + + def unique_config_key(self, node, value): + query = self.Session.query(tempmon.Probe)\ + .filter(tempmon.Probe.config_key == value) + if self.editing: + probe = self.get_instance() + query = query.filter(tempmon.Probe.uuid != probe.uuid) + if query.count(): + raise colander.Invalid(node, "Config key must be unique") + + def render_client(self, probe, field): + client = probe.client + if not client: + return "" + text = six.text_type(client) + url = self.request.route_url('tempmon.clients.view', uuid=client.uuid) + return tags.link_to(text, url) def delete_instance(self, probe): # bulk-delete all readings first diff --git a/tailbone/views/tempmon/readings.py b/tailbone/views/tempmon/readings.py index 4e4dc5b8..a9c6d2c2 100644 --- a/tailbone/views/tempmon/readings.py +++ b/tailbone/views/tempmon/readings.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8; -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2017 Lance Edgar +# Copyright © 2010-2018 Lance Edgar # # This file is part of Rattail. # @@ -26,13 +26,14 @@ Views for tempmon readings from __future__ import unicode_literals, absolute_import +import six from sqlalchemy import orm from rattail_tempmon.db import model as tempmon -import formalchemy as fa +from webhelpers2.html import tags -from tailbone.views.tempmon import MasterView, ClientFieldRenderer, ProbeFieldRenderer +from tailbone.views.tempmon import MasterView class TempmonReadingView(MasterView): @@ -56,6 +57,13 @@ class TempmonReadingView(MasterView): 'degrees_f', ] + form_fields = [ + 'client', + 'probe', + 'taken', + 'degrees_f', + ] + def query(self, session): return session.query(tempmon.Reading)\ .join(tempmon.Client)\ @@ -89,18 +97,32 @@ class TempmonReadingView(MasterView): def render_client_host(self, reading, column): return reading.client.hostname - def _preconfigure_fieldset(self, fs): - fs.client.set(label="TempMon Client", renderer=ClientFieldRenderer) - fs.probe.set(label="TempMon Probe", renderer=ProbeFieldRenderer) + def configure_form(self, f): + super(TempmonReadingView, self).configure_form(f) - def configure_fieldset(self, fs): - fs.configure( - include=[ - fs.client, - fs.probe, - fs.taken, - fs.degrees_f, - ]) + # client + f.set_renderer('client', self.render_client) + f.set_label('client', "Tempmon Client") + + # probe + f.set_renderer('probe', self.render_probe) + f.set_label('probe', "Tempmon Probe") + + def render_client(self, reading, field): + client = reading.client + if not client: + return "" + text = six.text_type(client) + url = self.request.route_url('tempmon.clients.view', uuid=client.uuid) + return tags.link_to(text, url) + + def render_probe(self, reading, field): + probe = reading.probe + if not probe: + return "" + text = six.text_type(probe) + url = self.request.route_url('tempmon.probes.view', uuid=probe.uuid) + return tags.link_to(text, url) def includeme(config):