summaryrefslogtreecommitdiffstats
path: root/ipawebui
diff options
context:
space:
mode:
authorJason Gerard DeRose <jderose@redhat.com>2010-01-26 06:39:00 -0700
committerRob Crittenden <rcritten@redhat.com>2010-01-26 10:32:44 -0500
commit7b571e369312ae5c246f1a90337c0d5980a6a538 (patch)
tree3f94d4c226ad93fa6d4e4c51651a1a2a5e22e6b5 /ipawebui
parente9dc9de23afa987e59b1dcfc1a0e9c21b4c1f472 (diff)
downloadfreeipa-7b571e369312ae5c246f1a90337c0d5980a6a538.tar.gz
freeipa-7b571e369312ae5c246f1a90337c0d5980a6a538.tar.xz
freeipa-7b571e369312ae5c246f1a90337c0d5980a6a538.zip
Enabled CRUDS in webUI using wehjit 0.2.0
Diffstat (limited to 'ipawebui')
-rw-r--r--ipawebui/engine.py124
-rw-r--r--ipawebui/widgets.py301
2 files changed, 227 insertions, 198 deletions
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 = """
- <div
- xmlns:py="http://genshi.edgewall.org/"
- py:if="mode == page_mode"
- py:strip="True"
- >
- <child py:for="child in children" py:replace="child.generate()" />
- </div>
- """
-
-
-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 = """
<div
xmlns:py="http://genshi.edgewall.org/"
- class="${klass}"
+ class="${css_classes}"
id="${id}"
>
- <table py:if="isinstance(result, dict)">
- <tr py:for="key in order" py:if="key in result">
- <th py:content="labels[key]" />
- <td py:content="result[key]" />
- </tr>
- </table>
-
- <table
- py:if="isinstance(result, (list, tuple)) and len(result) > 0"
- >
- <tr>
- <th
- py:for="key in order"
- py:if="key in result[0]"
- py:content="labels[key]"
- />
- </tr>
- <tr py:for="entry in result">
- <td
- py:for="key in order"
- py:if="key in result[0]"
- py:content="entry[key]"
+ <a
+ py:for="p in pages"
+ py:content="p.title"
+ href="${relurl(p.url)}"
/>
- </tr>
- </table>
</div>
"""
- 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 = """
- <input
- xmlns:py="http://genshi.edgewall.org/"
- type="hidden"
- name="${name}"
- />
+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 = """
- <p
- xmlns:py="http://genshi.edgewall.org/"
- class="${klass}"
- id="${id}"
- py:if="message"
- py:content="message"
- />
+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)