From 392ecb21fb990635d73dd50c0b118bf9a4719c7f Mon Sep 17 00:00:00 2001
From: Renaud Le Gac <renaud.legac@free.fr>
Date: Wed, 24 Feb 2010 21:32:28 +0000
Subject: [PATCH] Deploy the new web service cfgSvc. It is base on the
 Ext.Direct technology. In this approach the configuration of the form or grid
 are performed on demand.

---
 controllers/configuration.py      | 111 ++++++----
 modules/cfgsvc.py                 | 354 +++++++++++-------------------
 modules/foreignfield.py           |  69 ++++++
 static/appjs/appviewportintree.js | 113 ++++++----
 static/script/viewport_1.js       |  53 ++---
 views/applayout.html              |   2 +-
 6 files changed, 365 insertions(+), 337 deletions(-)
 create mode 100644 modules/foreignfield.py

diff --git a/controllers/configuration.py b/controllers/configuration.py
index 86487b93..8c7abfc7 100644
--- a/controllers/configuration.py
+++ b/controllers/configuration.py
@@ -1,19 +1,10 @@
 """ configuration.py
 
-	Controllers to interface the javascript application and database model.
-	It mainly return configuration object adapted to the UI.
-
-		url
-			http://localhost:8000/mdvPostInstall/configuration
-		
-		debug
-			post argument.
-			Print a lot of information when true
-		
-		exclude
-			post argument.
-			A list of tables for which configuration object are nor return.
-			
+	Controllers/router for the web service cfgSVc
+
+    Relies on Ext.Direct see specification:
+    http://www.extjs.com/products/extjs/direct.php
+	
 	Author: R. Le Gac
 	$Id$
 
@@ -21,37 +12,75 @@
 
 __version__ = "$Revision$"
 
-import pprint
+from applications.mdvPostInstall.modules.cfgsvc import CfgSvc
 
 from gluon.contrib import simplejson as json
-from gluon.http import HTTP
+from pprint import pprint
 
-from applications.mdvPostInstall.modules.cfgsvc import AppCfg
 
 def index():
-	""" controller handling application configuration object 
+    """ controller handling application configuration object 
 
-	Return a JSON string when the action is successful.
-	Otherwise return and HTTP error.
+    Act as a router for the cfgSvc service (see Ext;Direct Extjs 3.1.1)
+    Decode the raw HTTP post request:
+    {action: "cfgSvc", method: x, data: y, tip: i, type: "rpc"}
+    
+    Return a JSON string with the result of the request: 
+    {action: "cfgSvc", method: x, result: y, tip: i, type: "rpc"}
+    
+    Otherwise return and HTTP error.
 
-	"""
-	
-	debug = "debug" in request.vars and (request.vars.debug == 'true')
-	
-	if debug:
-		print "\nSTART CONFIGURATION CONTROLLER" 
-		print "POST arguments:", request.vars
-
-	try:
-		di = AppCfg(db).proceed(request.vars)
-		resp = json.dumps(di)
-
-	except BaseException, e:
-		raise HTTP(500, e)
-		
-	if debug:
-		print "\nCONFIGURATION CONTROLLER RESPONSE IS:"
-		pprint.pprint(di)
-		print "\nEND OF CONFIGURATION CONTROLLER\n"
-
-	return resp
+    For more detail on Ext.Direct see specification:
+    http://www.extjs.com/products/extjs/direct.php
+    
+    """
+
+    debug = True
+    
+    # NOTE: the server cfgSvc is start at the beginning
+    # when building the model (db.py)
+    
+    # decode the raw HTTP post
+    # ExtJs.3.1.1 {action: "xx", method: "y", data: [], type:"rpc", tid:2}
+    
+    req = json.loads(request.body.read())
+
+    if debug:
+        print "\nSTART CONFIGURATION CONTROLLER:" 
+        pprint(req)
+    
+    # receive a list of dictionary for a multi-request
+    li = []
+    if isinstance(req, list):
+        li.extend(req)
+    else:
+        li.append(req)
+    
+    for di in li:
+        # construct the command to be executed
+        args = di["data"]
+        cmd = "%s.%s(*args)" % (di["action"], di["method"])
+        
+        if args == None:
+            cmd = "%s.%s()" % (di["action"], di["method"])
+            
+        # execute the command and return HTTP exception
+        # when an internal error occurred
+        try:
+            res = eval(cmd)
+        except BaseException, e:
+            raise HTTP(500, e)
+    
+        # NOTE: the client expect the following object:
+        # ExtJs.3.1.1 {action: "xx", method: "y", result: [], type:"rpc", tid:2}
+        
+        del di["data"]
+        di["result"] = res 
+
+    if debug:
+        print "\nCONFIGURATION CONTROLLER RESPONSE IS:"
+        pprint(li)
+        print "\nEND OF CONFIGURATION CONTROLLER\n"
+
+    # encode the data as a json string
+    return json.dumps(li)
\ No newline at end of file
diff --git a/modules/cfgsvc.py b/modules/cfgsvc.py
index 8d6fe869..11f71b92 100644
--- a/modules/cfgsvc.py
+++ b/modules/cfgsvc.py
@@ -5,8 +5,8 @@
 __version__ = "$Revision$"
 
 
-from basesvc import BaseSvc, KEYWORD_MISSING
-from gluon.validators import IS_IN_DB
+from foreignfield import ForeignField
+
 
 # Convert a field type into a widget xtype
 FTYPE_TO_XTYPE = {'boolean':   'checkbox',\
@@ -32,262 +32,170 @@ def first_is_upper(field):
 	return "%s%s" % (field[0].upper(), field[1:])
 	
 	
-class AppCfg(BaseSvc):
+class CfgSvc:
 
-	foreign = None
-	form_models = {}
-	grid_models = {}
-	json_stores = {}
-	tables = []
-	
+	_db = None
+	_foreign = None	
 	
 	def __init__(self, db):
-		BaseSvc.__init__(self, db)
-		self.foreign = ForeignField(db)
 		
-	def generate_forms(self):
-		""" Return a dictionary with configuration for entry form.
+		self._db = db
+		self._foreign = ForeignField(db)
+
+
+	def _getColumnsModel(self, table):
+		""" Generate columns model required by the gridPanel widget.
+		The method return a list.
 		
 		"""
-		di = {}
-		for table in self.tables:
-			di[table] = {"xtype": "xentry",
-						"title": first_is_upper(table),
-						"table": table,
-						"items": self.form_models[table]}
-		return di
+		
+		li = []
+
+		for field in self._db[table].fields:
+			col = {}
+			
+			# replace foreign key by the pointing column
+			if self._foreign.is_foreign_field(table, field):
+				k_field = self._foreign[table][field]["k_field"]
+				col["header"] = first_is_upper(k_field)
+				col["dataIndex"] = k_field
+			
+			# standard column
+			else:
+				col["header"] = first_is_upper(field)
+				col["dataIndex"] = field
+				
+			col["sortable"] = True
+			
+			# hide the primary key
+			if field == "id":
+				col["hidden"] = True
 	
+			li.append(col)
 			
-	def generate_formModels(self):
-		""" Fill the attribute _form_models with formModels for selected table.
-		These configuration objects are used by the entryFormPanel and by the 
-		gridPanel widgets. 
-		
-		To avoid complication form_model will be copied in each widget in
-		due time. It is why there are kept in memory.
+		return li
+
+
+	def _getFormModelItems(self, table):
+		""" Return the list of items appearing in a Form model.
 		
 		"""
-		di = {}
-		for table in self.tables:
-			di[table] = []
-			
-			for el in self._db[table].fields:
-				cfg = {}
-				field = self._db[table][el]
+		li = []
+		
+		for el in self._db[table].fields:
+			cfg = {}
+			field = self._db[table][el]
 
-				# foreign key
-				if self.foreign.is_foreign_field(table, field.name):
-					
-					k = self.foreign.get_foreign_data(table, field.name)
+			# foreign key
+			if self._foreign.is_foreign_field(table, field.name):
 					
-					cfg["xtype"] = "xcombobox"
-					cfg["hiddenName"] = field.name
-					cfg["displayField"] = k["k_field"]
-					cfg["fieldLabel"] = first_is_upper(k["k_field"])
-					cfg["table"] = k["k_table"]
-					cfg["valueField"] = k["k_key"]
+				k = self._foreign.get_foreign_data(table, field.name)
 					
-				# standard field
-				else:
-					cfg["xtype"] = FTYPE_TO_XTYPE[field.type]
-					cfg["fieldLabel"] = first_is_upper(field.name)
-					cfg["name"] = field.name
-
-				# default value and not null
-				# NOTE: the entryform doesn't work when both default and
-				#       notnull condition are defined.
-				if field.default:
-					cfg["emptyText"] = str(field.default)
-				elif field.notnull:
-					cfg["allowBlank"] = False
+				cfg["xtype"] = "xcombobox"
+				cfg["hiddenName"] = field.name
+				cfg["displayField"] = k["k_field"]
+				cfg["fieldLabel"] = first_is_upper(k["k_field"])
+				cfg["table"] = k["k_table"]
+				cfg["valueField"] = k["k_key"]
 					
-				# hide primary key
-				if field.name == "id":
-					cfg["hidden"] = True
-					cfg["hideLabel"] = True
-					cfg["readOnly"] = True
+			# standard field
+			else:
+				cfg["xtype"] = FTYPE_TO_XTYPE[field.type]
+				cfg["fieldLabel"] = first_is_upper(field.name)
+				cfg["name"] = field.name
+
+			# default value and not null
+			# NOTE: the entryform doesn't work when both default and
+			#       notnull condition are defined.
+			if field.default:
+				cfg["emptyText"] = str(field.default)
+			elif field.notnull:
+				cfg["allowBlank"] = False
 				
-				# format
-				if field.type == "date":
-					cfg["format"] = "Y-m-d"
-
+			# hide primary key
+			if field.name == "id":
+				cfg["hidden"] = True
+				cfg["hideLabel"] = True
+				cfg["readOnly"] = True
+				
+			# format
+			if field.type == "date":
+				cfg["format"] = "Y-m-d"
 				if field.type == "datetime":
 					cfg["format"] = "Y-m-d H:i"
 				
-				di[table].append(cfg)
-		
-		self.form_models = di
-
-
-	def generate_gridModels(self):
-		""" Generate gridModel requires by the gridPanel widget.
-		Foreign key are replace by the pointing columns.
-		
-		"""
-		di = {}
-		
-		for table in self.tables:
-			di[table] = []
-			for field in self._db[table].fields:
-				col = {}
-				
-				# replace foreign key by the pointing column
-				if self.foreign.is_foreign_field(table, field):
-					k_field = self.foreign[table][field]["k_field"]
-					col["header"] = first_is_upper(k_field)
-					col["dataIndex"] = k_field
-				
-				# standard column
-				else:
-					col["header"] = first_is_upper(field)
-					col["dataIndex"] = field
-					
-				col["sortable"] = True
-				
-				# hide the primary key
-				if field == "id":
-					col["hidden"] = True
-		
-				di[table].append(col)
-
-		self.grid_models = di
-
-
-	def generate_jsonStores(self):
-		""" Generate configuration object for JSON stores.
-		They are require by the gridPanel widget.
-		
-		"""
-		di = {}
-		
-		for table in self.tables:
-			di[table] = {"table": table}
-			di[table]["debug"] = False
-			di[table]["tableFields"] = self._db[table].fields
+			li.append(cfg)
 			
-			if table in self.foreign:
-				di[table]["foreignFields"] = []
-				for field in self.foreign[table]:
-					k = self.foreign[table][field]
-					li = [field, k["k_table"], k["k_field"]]
-					di[table]["foreignFields"].append(li)
-			
-		self.json_stores = di
-
+		return li
 
-	def generate_grids(self):
-		""" Generate the configuration object for the gridPanel widgets.
-		The configuration of JSON store, formModel and gridModel have
-		to be generated before.
-		
-		"""
-		di = {}
 	
-		for table in self.tables:
-			di[table] = {}
-			di[table]["xtype"] = "xgrid"
-			di[table]["colModel"] = self.grid_models[table]
-			di[table]["formModel"] = self.form_models[table]
-			di[table]["store"] = self.json_stores[table]
-			di[table]["table"] = table
-			di[table]["title"] = first_is_upper(table)
-
-		return di
-
+	def _getJsonStore(self, table):
+		""" Generate configuration object for JSON stores 
+		required by the gridPanel widget.
 		
-	def proceed(self, vars):
-		"""Proceed the request sends via the POST/GET method.
-		Return a dictionary with the configuration object
-
 		"""
 		
-		BaseSvc.proceed(self, vars)
-		
-		self.select_tables()
-		self.generate_formModels()
-		self.generate_jsonStores()
-		self.generate_gridModels()
+		di = {"table": table}
 
-		di = {}
-		di["form"] = self.generate_forms()
-		di["grid"] = self.generate_grids()
+		di["debug"] = False
+		di["tableFields"] = self._db[table].fields
 		
-		return di
-
-
-	def select_tables(self):
-		""" build the list of selected table.
-		Some tables can be removed from the UI using the keyword exclude.
-		
-		"""
-		excluded_tables = []
-		if "exclude" in self._vars:
-			excluded_tables = self._list(self._vars["exclude"])
+		if table in self._foreign:
+			di["foreignFields"] = []
+			for field in self._foreign[table]:
+				k = self._foreign[table][field]
+				li = [field, k["k_table"], k["k_field"]]
+				di["foreignFields"].append(li)
 			
-		self.tables = list(self._db.tables)
-		for table in self._db.tables:
-			if table in excluded_tables:
-				self.tables.pop(self.tables.index(table))
+		return di
 		
 		
-
-class ForeignField(dict):
-	
-	def __init__(self, db):
-		""" Scan the database model to identify foreign key,
-		Store the pointing table and field.
+	def _getMethods(self):
+		""" Return the list of methods available and 
+		their number of arguments.
 		
 		"""
-
-		for table in db.tables:
-			fields = [db[table][el] for el in db[table].fields]
-			
-			for field in fields:
-				#
-				# FOREIGN FIELD
-				#
-				# The reference to the foreign table is defined in the
-				# type: "reference foreignTable".
-				# The foreign table and the associated column are also
-				# defined in the validator IS_IN_DB.
-				#
-				if field.type.startswith("reference"):
-				
-					validators = field.requires
-					if not isinstance(validators, (list, tuple)):
-						validators = [field.requires]
-				
-					for vdt in validators:
-						if isinstance(vdt, IS_IN_DB):
-							
-							if table not in self:
-								self[table] = {}
-								
-							self[table][field.name] = {}
-							self[table][field.name]["k_table"] = vdt.ktable
-							self[table][field.name]["k_field"] = vdt.ks[0]
-							self[table][field.name]["k_key"] = vdt.ks[1] 
-							
+		li = []
+		for el in dir(self):
+			if el.startswith("_"): continue
+			di = {"name": el,\
+				  "len": eval("self.%s.func_code.co_argcount" % el)-1}
+			li.append(di)
+
+		print li
+		return li
 	
-	def is_foreign_field(self, table, field):
-		""" Return true is the table.field is a foreign key.
 		
-		"""
-		if table in self:
-			return field in self[table]
+	def getFormModel(self, table):
+		""" Return the configuration dictionary for an entryForm widget.
 		
-		else:
-			return False
+		"""
+		di = {"xtype": "xentry",
+			  "title": first_is_upper(table),
+			  "table": table,
+			  "items": self._getFormModelItems(table)}
+		return di
+
 		
-		 
-	def get_foreign_data(self, table, field):
-		""" Return a dictionary containing the pointing table, field and key.
-		Otherwise return None.
+	def getGridModel(self, table):
+		""" Return the configuration dictionary for a gridPanel widget.
 		
 		"""
-		if self.is_foreign_field(table, field):
-			return self[table][field]
-		
-		else:
-			return None
+		di = {}
+	
+		di["xtype"] = "xgrid"
+		di["colModel"] = self._getColumnsModel(table)
+		di["formModel"] = self._getFormModelItems(table)
+		di["store"] = self._getJsonStore(table)
+		di["table"] = table
+		di["title"] = first_is_upper(table)
 
+		return di
+
+	def getTables(self, *args):
+		""" Return a the list of tables.
+		
+		"""
+		li = list(self._db.tables)
+		li.sort()
+		return li
\ No newline at end of file
diff --git a/modules/foreignfield.py b/modules/foreignfield.py
new file mode 100644
index 00000000..895541f4
--- /dev/null
+++ b/modules/foreignfield.py
@@ -0,0 +1,69 @@
+""" $Id$
+	Author: R. Le Gac
+"""
+
+__version__ = "$Revision$"
+
+
+from gluon.validators import IS_IN_DB
+
+class ForeignField(dict):
+	
+	def __init__(self, db):
+		""" Scan the database model to identify foreign key,
+		Store the pointing table and field.
+		
+		"""
+
+		for table in db.tables:
+			fields = [db[table][el] for el in db[table].fields]
+			
+			for field in fields:
+				#
+				# FOREIGN FIELD
+				#
+				# The reference to the foreign table is defined in the
+				# type: "reference foreignTable".
+				# The foreign table and the associated column are also
+				# defined in the validator IS_IN_DB.
+				#
+				if field.type.startswith("reference"):
+				
+					validators = field.requires
+					if not isinstance(validators, (list, tuple)):
+						validators = [field.requires]
+				
+					for vdt in validators:
+						if isinstance(vdt, IS_IN_DB):
+							
+							if table not in self:
+								self[table] = {}
+								
+							self[table][field.name] = {}
+							self[table][field.name]["k_table"] = vdt.ktable
+							self[table][field.name]["k_field"] = vdt.ks[0]
+							self[table][field.name]["k_key"] = vdt.ks[1] 
+							
+	
+	def is_foreign_field(self, table, field):
+		""" Return true is the table.field is a foreign key.
+		
+		"""
+		if table in self:
+			return field in self[table]
+		
+		else:
+			return False
+		
+		 
+	def get_foreign_data(self, table, field):
+		""" Return a dictionary containing the pointing table, field and key.
+		Otherwise return None.
+		
+		"""
+		if self.is_foreign_field(table, field):
+			return self[table][field]
+		
+		else:
+			return None
+
diff --git a/static/appjs/appviewportintree.js b/static/appjs/appviewportintree.js
index 46f99ba4..819e9abc 100644
--- a/static/appjs/appviewportintree.js
+++ b/static/appjs/appviewportintree.js
@@ -5,25 +5,28 @@
  * This plugin add a topNode in the tree which contains child.
  * When a child is clicked a new tab appears in the tab panel.
  * 
- * The plugin requires that the property model is set.
- * It is a dictionary containing the configuration for the object which
- * will be created in the tab. 
+ * The name of the child nodes are defined by the property 'nodes'.
+ * For example the name of the tables for a database application.
  * 
- * The key is the name of the child node appearing in the tree, 
- * i.e name of the table in a database applications
+ * The plugin request to the server the model of widget embedded 
+ * in the tab using the cfgSvc web service.
+ * The type of the widget has to be defined through the property wdgType.
+ * In the current implementation 'xentry' and 'xgrid' are recognized: . 
  * 
  * The ptype of this component is pintree.
  *  
  * MANDATORY PROPERTIES:
  * 		- models
  * 		- topNodeName
+ * 		- nodes
+ * 		- wdgType
  * 
  * NOTE:
  * 		- the id of leaf node are defined as:
- * 		  /App.name/TopNodeName/key
+ * 		  /App.name/TopNodeName/node
  * 
  * 		- the id of create tab is equal to the id of the node:
- * 		  /App.name/TopNodeName/key
+ * 		  /App.name/TopNodeName/node
  * 
  * @author legac
  * @version $Id$
@@ -32,19 +35,24 @@
 Ext.namespace('App.viewport');
 
 App.viewport.InTreePanel = Ext.extend(Object, {
-	/**
-	 * @cfg {Object} models configuration object describing 
-	 * the object encapsulated in the tab panel.
-	 * This object can be provided by the server.
-	 */
-	models: null,
-	
 	/**
 	 * @cfg {String} topNodeName name of the top node associate to this plugin.
 	 * 
 	 */
 	topNodeName: null,
 	
+	/**
+	 * @cfg {Array} nodes list of names for the children nodes
+
+	 */
+	nodes: null,
+
+	/**
+	 * @cfg {String} wdgType type of the widget embeded in the tab.
+	 * The current version of this pulgin understand 'xentry' and 'xgrid'
+	 */
+	wdgType: null,
+		
 	/**
 	 * Private parameters referring to the viewport
 	 */	
@@ -77,11 +85,11 @@ App.viewport.InTreePanel = Ext.extend(Object, {
 		root.appendChild(node);
 		
 		//add the children and the associated handler
-		for(item in this.models){
+		for (var i = 0; i < this.nodes.length; i++){
 			
 			var child = new Ext.tree.TreeNode({
-				id: "/"+App.name+"/"+this.topNodeName+"/"+item,
-				text: this.models[item].title,
+				id: "/"+App.name+"/"+this.topNodeName+"/"+this.nodes[i],
+				text: this.nodes[i],
 				leaf: true,
 			});
 			
@@ -89,52 +97,77 @@ App.viewport.InTreePanel = Ext.extend(Object, {
 			child.on('click', this.onCreateTab, this);
 		}
 	},
-	
+
 	/**
-	 * Handler to create a tab when a node is click
-	 * @param {Object} node Ext.treeTreeNode
+	 * Private function to create the widget embedded in the tab
+	 * Its configuration is requested to the server via the cfgSvc service
+	 * 
+	 * NOTE: 
+	 * The underlying technic relies on Ext.Direct (Extjs 3.1.1)
+	 * 
+	 * @param {Object} provider
+	 * @param {Object} response
 	 */
-	onCreateTab: function(node){
-
-		// is the tab already exists
-		var tabId = node.id;
-		if(this.viewport.tabPanel.getItem(tabId)){
-			this.viewport.tabPanel.setActiveTab(tabId);
-			return;
-		}
-		
-		// retrieve the name of the table
-		// retrieve the name of the top node
-		var li = tabId.split("/").reverse();
-		var table = li[0];
-		var topNode = li[1];
+	createNewTab: function(provider, response){
 		
+		var model = response.result;
+
+		// The id of the node is equal to the id of the tab
+		var tabId = "/"+App.name+"/"+this.topNodeName+"/"+model.table
+
 		// instantiate the object to be load in this tab.
 		// Special processing is require for xgrid
-		if (this.models[table].xtype == "xgrid") {
+		if (model.xtype == "xgrid") {
 			var gridConfigurator = new App.grid.Configurator({
 				debug: App.debug,
 				dbUrl: App.dburl,
-				gridModel: this.models[table],
+				gridModel: model,
 			});
 			var wdg = gridConfigurator.getGrid();
 
 		} else {
-			var cfg = this.models[table];
-			var wdg = Ext.ComponentMgr.create(cfg);		
+			var wdg = Ext.ComponentMgr.create(model);		
 		}
-		
+
 		// create a panel with the user widget and the tab
 		var pan = new Ext.Panel({
 			id: tabId,
 			closable: true,
-			title: topNode+" "+table,
+			title: this.topNodeName+" "+model.table,
 			items: [wdg],
 		});
 				
 		var tab = this.viewport.tabPanel.add(pan);
 		this.viewport.tabPanel.setActiveTab(tab.id);
 		
+	},	
+	/**
+	 * Handler to create a tab when a node is click
+	 * @param {Object} node Ext.treeTreeNode
+	 */
+	onCreateTab: function(node){
+
+		// is the tab already exists
+		var tabId = node.id;
+		if(this.viewport.tabPanel.getItem(tabId)){
+			this.viewport.tabPanel.setActiveTab(tabId);
+			return;
+		}
+		
+		// retrieve the name of the table from the tabId
+		// /App.name/TopNodeName/table
+		var li = tabId.split("/").reverse();
+		var table = li[0];
+
+		// request the configuration object and instanciate it
+		if (this.wdgType == 'xentry')
+			cfgSvc.getFormModel(table, this.createNewTab, this);
+
+		else if (this.wdgType == 'xgrid')
+			cfgSvc.getGridModel(table, this.createNewTab, this);
+			
+		else
+			throw new Error("the poperty wdgType for App.viewport.InTreePanel is not defined.")
 	},
 });
 
diff --git a/static/script/viewport_1.js b/static/script/viewport_1.js
index 739354bb..c81ce440 100644
--- a/static/script/viewport_1.js
+++ b/static/script/viewport_1.js
@@ -1,52 +1,48 @@
 /**
  * viewport_1.js
- * To test and debug application viewport.
+ * To test and debug application viewport using remote service.
  * 
  * $Id$
  * 
- * TODO: the editform widget does not dialog with the database ? why ?
- * TODO: create configuration object with layout
- * 
  */
 
 /**
  * main function
- * The scope, this, contains the models return by the server
+ * 
  */
 
-var main = function(){
 
-	// configuration model
-	var model = this;
-	
-//	console.log("Models");
-//	console.dir(model);
+var main = function(provider, response){
 
-//	console.log("Model form");
-//	console.dir(model.form);
+	// list of tables removing excluded tables
+	var tables = response.result.filter(function(element, index, array){
+		return App.excludedTables.indexOf(element) == -1 ? true : false
+	});
 
+	
 	/*
 	 * Plugin to handle entryform
 	 */
 	var formInTree = {
-		models: model.form,
 		topNodeName: 'Forms',
+		nodes: tables,
+		wdgType: 'xentry',
 		ptype: 'pintree',
 	};
 
+
 	/*
 	 * Plugin to handle grid
 	 */	 	
 	var tableInTree = {
-		models: model.grid,
 		topNodeName: 'Tables',
+		nodes: tables,
+		wdgType: 'xgrid',
 		ptype: 'pintree',
 	};
 	 
 	/*
 	 * Pre-configured viewport with a treepanel and a tab panel
-	 * The id of the root node is App.name
-	 * the id of the first tab is /tab/welcome
 	 */
 
 	var cfg = Ext.apply({
@@ -61,20 +57,13 @@ Ext.onReady(function(){
 
     Ext.QuickTips.init();
 
-	// Request widget models from the server
-	// It is strongly relate'd to the database model
-	var models = new App.Cfg({
-		url: App.cfgurl,
-	});
-
-	// The response of the server is asynchronous.
-	// When the model is load launch the main function
-	models.on('cfgloaded', main, models);
-
-	//request the models from the server
-	models.load({
-		debug: App.debug,
-		exclude: ["systemsAddRpms", "systemsRemoveRpms"],
-	})
+	// Expose the remote service cfgSvc
+	Ext.Direct.addProvider(App.cfgSvcMethods);
 
+	// Define list of  tables not shown in the user interface
+	App.excludedTables = ["systemsAddRpms", "systemsRemoveRpms"];
+	
+	// Request the list of tables and launch the main application
+	cfgSvc.getTables(main);
+	
 });
\ No newline at end of file
diff --git a/views/applayout.html b/views/applayout.html
index d0b8daac..6354958b 100644
--- a/views/applayout.html
+++ b/views/applayout.html
@@ -25,7 +25,7 @@
 			App.name = '{{=request.application}}';
 			App.debug = {{=str(appdebug).lower()}};
 			App.cfgSvcMethods = {
-				"url": '/{{=request.application}}/foo',
+				"url": '/{{=request.application}}/configuration',
 				"type":"remoting",
 				"actions": {
 					"cfgSvc": {{=cfgSvcMethods}}
-- 
GitLab