From 7b571e369312ae5c246f1a90337c0d5980a6a538 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 26 Jan 2010 06:39:00 -0700 Subject: Enabled CRUDS in webUI using wehjit 0.2.0 --- ipawebui/engine.py | 124 ++++++++++++++-------- ipawebui/widgets.py | 301 ++++++++++++++++++++++++++-------------------------- 2 files changed, 227 insertions(+), 198 deletions(-) (limited to 'ipawebui') diff --git a/ipawebui/engine.py b/ipawebui/engine.py index a90a450d..01b271a9 100644 --- a/ipawebui/engine.py +++ b/ipawebui/engine.py @@ -65,7 +65,17 @@ class ParamMapper(object): ) +def filter_params(namespace): + for param in namespace(): + if param.exclude and 'webui' in param.exclude: + continue + yield param + + class Engine(object): + + cruds = frozenset(['add', 'show', 'mod', 'del', 'find']) + def __init__(self, api, app): self.api = api self.app = app @@ -86,11 +96,21 @@ class Engine(object): ) def build(self): - for cmd in self.api.Object.user.methods(): - self.pages[cmd.name] = self.build_page(cmd) - for page in self.pages.itervalues(): - page.menu.label = 'Users' - self.add_object_menuitems(page.menu, 'user') + for obj in self.api.Object(): + if self.cruds.issubset(obj.methods) and obj.primary_key is not None: + self.pages[obj.name] = self.build_cruds_page(obj) + + # Add landing page: + landing = self.app.new('PageApp', id='', title='Welcome to FreeIPA') + + for page in self.pages.values() + [landing]: + page.menu.label = 'FreeIPA' + for name in sorted(self.pages): + p = self.pages[name] + page.menu.new_child('MenuItem', label=p.title, href=p.url) + + + # Add in the info pages: page = self.app.new('PageApp', id='api', title='api') @@ -110,6 +130,58 @@ class Engine(object): ) ) + def build_cruds_page(self, obj): + page = self.app.new('PageGrid', title=obj.name, id=obj.name) + + # Setup CRUDS widget: + page.cruds.autoload = True + page.cruds.jsonrpc_url = self.api.Backend.jsonserver.url + page.cruds.key = obj.primary_key.name + page.cruds.method_create = obj.methods['add'].name + page.cruds.method_retrieve = obj.methods['show'].name + page.cruds.method_update = obj.methods['mod'].name + page.cruds.method_delete = obj.methods['del'].name + page.cruds.method_search = obj.methods['find'].name + page.cruds.display_cols = tuple( + dict( + name=p.name, + label=p.label, + css_classes=None, + ) + for p in obj.params() + ) + + # Setup the Grid widget: + page.grid.cols = tuple( + dict( + name=p.name, + label=p.label, + css_classes=None, + ) + for p in obj.params() if p.required + ) + + + # Setup the create Dialog: + cmd = obj.methods['add'] + page.create.title = cmd.summary.rstrip('.') + for p in filter_params(cmd.params): + page.create.fieldtable.add(self.param_mapper(p, cmd)) + + # Setup the retrieve Dialog + page.retrieve.title = 'Showing "{value}"' + + # Setup the update Dialog: + page.update.title = 'Updating "{value}"' + cmd = obj.methods['mod'] + for p in filter_params(cmd.options): + page.update.fieldtable.add(self.param_mapper(p, cmd)) + + # Setup the delete Dialog + page.delete.title = 'Delete "{value}"?' + + return page + def build_info_page(self, kind): # Add in the Object page: plugins = tuple(self.api[kind]()) @@ -126,45 +198,3 @@ class Engine(object): self.app.new(kind) ) return page - - def build_page(self, cmd): - page = self.app.new('PageCmd', - cmd=cmd, - id=cmd.name, - title=cmd.summary.rstrip('.'), - ) - page.form.action = page.url - page.form.method = 'GET' - page.form.add( - self.app.new('Hidden', name='__mode__', value='output') - ) - page.notification = self.app.new('Notification') - page.view.add(page.notification) - page.prompt = self.make_prompt(cmd) - page.show = self.make_show(cmd) - self.conditional('input', page.actions, self.app.new('Submit')) - self.conditional('input', page.view, page.prompt) - self.conditional('output', page.view, page.show) - return page - - def conditional(self, mode, parent, *children): - conditional = self.app.new('Conditional', mode=mode) - conditional.add(*children) - parent.add(conditional) - - def make_prompt(self, cmd): - table = self.app.new('FieldTable') - for param in self._iter_params(cmd.params): - table.add( - self.param_mapper(param, cmd) - ) - return table - - def make_show(self, cmd): - return self.app.new('Output') - - def _iter_params(self, namespace): - for param in namespace(): - if param.exclude and 'webui' in param.exclude: - continue - yield param diff --git a/ipawebui/widgets.py b/ipawebui/widgets.py index 1cf1adb9..d05b5b4e 100644 --- a/ipawebui/widgets.py +++ b/ipawebui/widgets.py @@ -228,169 +228,170 @@ class Object(base.Widget): """ - -class Conditional(base.Container): - - mode = Static('mode', default='input') - - @DynamicProp - def page_mode(self): - if self.page is None: - return - return self.page.mode - - xml = """ -
- -
- """ - - -class Output(base.Widget): - """ - Shows attributes form an LDAP entry. - """ - - order = Dynamic('order') - labels = Dynamic('labels') - result = Dynamic('result') +class LandingPage(base.Widget): + pages = Static('pages', default=tuple()) xml = """
- - - -
- -
- - - - - - -
-
-
""" - style = ( - ('table', ( - ('empty-cells', 'show'), - ('border-collapse', 'collapse'), - )), - - ('th', ( - ('text-align', 'right'), - ('padding', '.25em 0.5em'), - ('line-height', '%(height_bar)s'), - ('vertical-align', 'top'), - )), - ('td', ( - ('padding', '.25em'), - ('vertical-align', 'top'), - ('text-align', 'left'), - ('line-height', '%(height_bar)s'), - )), - ) - - -class Hidden(base.Field): - xml = """ - +class Form(builtins.Form): + js_class = 'Form' + + javascript = """ + Wehjit.bases.Form = new Class({ + Extends: Wehjit.bases.Widget, + + post_init: function() { + this.focused = null; + $each(this.el.elements, function(field) { + field.connect('focus', this); + }, this); + var parent = this.get_parent(); + if (parent && parent.klass == 'Dialog') { + parent.addEvent('run', this.on_run.bind(this)); + this.parent = parent; + } + this.formdata = null; + }, + + on_focus: function(field, event) { + this.focused = field; + }, + + on_run: function(dialog, params) { + console.assert(dialog == this.parent); + this.refocus(); + }, + + refocus: function() { + console.log('refocus', this.id, this.focused); + if (this.focused) { + this.focused.focus(); + return true; + } + if (this.el.elements.length > 0) { + this.el.elements[0].focus(); + return true; + } + return false; + }, + + get_data: function() { + console.log('Form.get_data'); + var rawdata = this.el.get_data(); + var data = {}; + + if (this.formdata == null) { + $each(rawdata, function(value, key) { + if (value !== '') { + data[key] = value; + } + }); + } + else { + $each(rawdata, function(value, key) { + var old = this.formdata[key]; + if (old == undefined && value === '') { + return; + } + if (old != value) { + console.log('changed: %s = %s', key, value); + data[key] = value; + } + }, this); + } + + return data; + + }, + + set_data: function(data) { + console.log('Form.set_data', data); + this.focused = null; + if ($type(data) == 'object') { + this.formdata = data; + } + else { + this.formdata = null; + } + this.el.set_data(data); + }, + + reset: function() { + this.formdata = null; + this.focused = null; + this.el.reset(); + }, + + }); """ -class Notification(base.Widget): - message = Dynamic('message') - error = Dynamic('error', default=False) - - @property - def extra_css_classes(self): - if self.error: - yield 'error' - else: - yield 'okay' - - xml = """ -

+class CRUDS(builtins.CRUDS): + display_cols = Static('display_cols', json=True, default=tuple()) + + +class Display(builtins.Display): + cols = None + + javascript = """ + Wehjit.bases.Display = new Class({ + Extends: Wehjit.bases.Widget, + + post_init: function() { + var parent = this.get_parent(); + console.assert(parent); + parent.addEvent('run', this.on_run.bind(this)); + this.cruds = Wehjit.get('cruds'); + this.cols = this.cruds.data.display_cols; + console.assert(this.cols); + if (this.cols.length == 0) { + this.cols = Wehjit.data.grid.cols; + } + }, + + on_run: function(dialog, row) { + console.log('Display.on_run(%s, %s)', dialog, row); + this.el.empty(); + if ($type(row) != 'object') { + return; + } + this.cols.each(function(col) { + var tr = new Element('tr'); + var th = new Element('th'); + th.textContent = col.label + ':'; + tr.appendChild(th); + this.el.appendChild(tr); + var td = new Element('td'); + var value = row[col.name]; + if ($type(value) == 'array') { + var value = value.join(','); + } + if ($type(value) != 'string') { + var value = ''; + } + td.textContent = value; + tr.appendChild(td); + }, this); + }, + + }); """ - style = ( - ('', ( - ('font-weight', 'bold'), - ('-moz-border-radius', '100%%'), - ('background-color', '#eee'), - ('border', '2px solid #966'), - ('padding', '0.5em'), - ('text-align', 'center'), - )), - ) -class PageCmd(builtins.PageApp): - cmd = Static('cmd') - mode = Dynamic('mode', default='input') - - def controller(self, environ): - query = extract_query(environ) - self.mode = query.pop('__mode__', 'input') - if self.mode == 'input': - return - soft = self.cmd.soft_validate(query) - errors = soft['errors'] - values = soft['values'] - if errors: - self.mode = 'input' - for key in self.form: - if key in errors: - self.form[key].error = errors[key] - if key in values: - self.form[key].value = values[key] - return - output = self.cmd(**query) - if isinstance(output, dict) and 'summary' in output: - self.notification.message = output['summary'] - params = self.cmd.output_params - if params: - order = list(params) - labels = dict((p.name, p.label) for p in params()) - else: - order = sorted(entry) - labels = dict((k, k) for k in order) - self.show.order = order - self.show.labels = labels - self.show.result = output.get('result') def create_widgets(): @@ -401,12 +402,10 @@ def create_widgets(): widgets.register(IPAPlugins) widgets.register(Command) widgets.register(Object) - widgets.register(Conditional) - widgets.register(Output) - widgets.register(Hidden) - widgets.register(Notification) - - widgets.register(PageCmd) + widgets.register(LandingPage) + widgets.register(Form, override=True) + widgets.register(CRUDS, override=True) + widgets.register(Display, override=True) freeze(widgets) -- cgit