[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
someindex
someindex2
- testdb
+ tables
- events
someevent
someevent2
+ mysql
+ information_schema
If we hit refresh. Then the following paths will be sent to the server:
root.sakila.tables.country.indexes
root.sakila.tables.film
root.testdb.events
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 :)
Bye,
Rouslan
More information about the Developers
mailing list