[Phpmyadmin-devel] GSoC Removal of Frames : New Navigation

Rouslan Placella rouslan at placella.com
Tue Jul 3 15:50:18 CEST 2012

On 02/07/12 21:28, Dieter Adriaenssens wrote:
> Hi Rouslan,
> I was just reading your weekly report. I have a question about the
> 'refreshing of navigation' :
> You mention that the state of the navigation (which branches are open)
> has to be remembered, when sending it over to the client/browser. Does

I think that I just worded it badly. The state of the tree is never, in 
fact, recorded anywhere. Instead it's calculated with a JS function.

> this mean that the entire navigation tree is generated server side on
> every change to the nav tree (f.e. clicking on a branch to open it, or

When clicking on a branch to open, only that branch, its immediate 
children and all its parents are loaded into memory. Then only its 
immediate children are rendered into HTML.

> when tables/databases are added/deleted/renamed/...)? Or only in case
> of a full refresh (or first load)?

On first load, only the list of databases (limited by $cfg[' 
MaxDbList']) is loaded into memory and rendered.

A full refresh is used for when a db/table is added, removed, renamed, 
copied, etc. During the full refresh, only the nodes that were visible 
before the refresh are loaded into memory and rendered. The only 
expection to this are tables, as any request to render a table will 
force their children to also be loaded and rendered. The idea here seems 
nice as we can avoid some extra ajax requests after loading a list of 
tables. However this proved to be slow during full refreshes as all 
index and column information my have to be loaded for dozens of tables.

> Would it make sense to keep the nav tree state stored client side and
> let the script repopulate the tree based on data it gets from the
> server, after a request initiated by user interaction (navigating the
> tree) or when the server sends new/changed/deleted tables when
> something is changed by the user in the main panel (triggering
> refreshNavigation)?
> Or would this overcomplicate things?

Sorry, I'm not sure what you are trying to say here. That said, I 
haven't really explained to anyone how the whole thing works, so maybe I 
should do that. So here is the basic workflow as it is currently in my repo:

During the initial page load, the navigation is not sent to the client 
at all, but just the links at the top of the panel and the logo.

As soon as the ready event is fired on the page, the list of databases 
is fetched via ajax. During this request only these databases are loaded 
into memory and rendered (but none of their children).

Then when a user clicks on a link to expand a particular branch, the 
path to that node (at this point it's just "root.sakila", for example) 
is sent to the server. The server will then load the databases into 
memory and check what kind of items are present in the db (tables, 
views, procedures, events). If there are more than one type of items, 
then containers for them (but not the items themselves) are loaded into 
memory, rendered and sent back to the client. Otherwise, if there are 
only tables present in a db, then the tables themselves are loaded into 
memory, rendered and sent back.

Let's say that we have tables and events in the sakila db and we opened 
its branch. At this point the list of containers is received from the 
server and attached to the sakila node. If we click on "Tables", the 
following path is sent to the server "root.sakila.tables" and in the 
reply we will receive the list of tables and for each table a list of 
columns and a list of indexes, if any.

This gets a bit more complicated when nodes are grouped. Whether this 
happens depends on the names of items and the 
$cfg['LeftFrameDBSeparator'], $cfg['LeftFrameTableSeparator '] and 
$cfg['LeftFrameTableLevel'] directives.
If we have a hyphen as a db separator and sakila_one and sakila_two dbs, 
then when we try to expand the tables branch in sakila_one, the 
following paths will be sent to the server for processing: actual_path 
-> "root.sakila_two.tables"; virtual_path -> "root.sakila_.two.Tables".

As far as refreshing goes, there is a JS function that traverses the 
rendered tree on the page and finds the deepest nodes in the hierarchy 
that have a "minus" icon near them. Then the list paths to these node is 
compiled and sent to the server. The server then knows how deep to load 
each branch into memory and which parts should be rendered. Let's look 
at a concrete example. Here's a tree that we have started browsing:

+ phpmyadmin
- sakila
     - film
         + columns
     + film_actor
     - country
         + columns
         - indexes
- testdb
     + tables
     - events
+ mysql
+ information_schema

If we hit refresh. Then the following paths will be sent to the server:


The server will load into memory, all tables, columns and indexes from 
sakila and render all of them. It will check if there are still tables 
in testdb, but it won't load any of them. And it will load and render 
the events from testdb. The resulting HTML code is then sent back to the 
server and the tree that is on the page is simply swapped for the new one.

The improvements that I was talking about on the blog for this system 
would be partial refreshes and removal of preloading for children of 
table nodes.

* Partial refreshes would be nice when we add/modify a table, for 
example. In this case, we only need to reload the database, not the 
whole tree, but we need to know which database to reload, so it would be 
necessary to pass some parameters to the refreshing function, which at 
the moment takes none.

* Preloading of indexes and columns for tables seemed like a good idea 
when I was first writing the code, but I didn't foresee that it would 
considerable slow down the refreshing of the tree, so it need to go.

I hope this makes it clearer how things are done in the new navigation. 
Feel free to ask if there are still things that are unclear, and any 
suggestion are always welcome :)


More information about the Developers mailing list