diff options
author | Farrell Wymore <farrell.wymore@windriver.com> | 2014-05-21 15:15:08 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2014-05-21 16:47:01 +0100 |
commit | defe2271350c36605704129f4a6b9332446a1319 (patch) | |
tree | 36fc9a72b47733f542ed90e47f80a0b692bc44ab /bitbake/lib/toaster/toastergui | |
parent | 8a8d7176fc830ec48248929e2ab79501dd2a2422 (diff) | |
download | ast2050-yocto-poky-defe2271350c36605704129f4a6b9332446a1319.zip ast2050-yocto-poky-defe2271350c36605704129f4a6b9332446a1319.tar.gz |
bitbake: toaster: sort columns properly after edit columns
If a sorted column is made invisible through the edit columns function,
resort the table the its default order.
[YOCTO 5919]
(Bitbake rev: 64618f7489eb9eb13a97d03cd2d353384f5faa70)
Signed-off-by: Farrell Wymore <farrell.wymore@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastergui')
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/basetable_top.html | 172 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/views.py | 46 |
2 files changed, 204 insertions, 14 deletions
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_top.html b/bitbake/lib/toaster/toastergui/templates/basetable_top.html index 22c3897..1231e1f 100644 --- a/bitbake/lib/toaster/toastergui/templates/basetable_top.html +++ b/bitbake/lib/toaster/toastergui/templates/basetable_top.html @@ -1,17 +1,42 @@ {% load projecttags %} <!-- component to display a generic table --> <script> - function showhideTableColumn(clname, sh) { - if (sh) $('.' + clname).show(100); - else $('.' + clname).hide(100); - // save cookie for all checkboxes - save = ''; - $('.chbxtoggle').each(function() { if ($(this).attr('id') != undefined) { save += ';' + $(this).attr('id') +':'+ $(this).is(':checked')} }) - $.cookie('_displaycols_{{objectname}}', save); - save = ''; - } + // + // most of the following javascript is for managing the 'Edit Columns' + // pop-up dialog and actions. the idea is that there are 2 types + // of actions: immediate - performed while the dialog is still + // visible - hide/show columns, and delayed - performed when the + // dialog becomes invisible - any resorting if necessary. + // + // When the dialog is open, an interval timer is set up to + // determine if the dialog is still visible. when the dialog + // closes - goes invisible, the delayed actions are performed. + // + // the interval timer and interrupt handler is a way of simulating + // an onclose event. there is probably a simpler way to do this + // however the pop-up window id was elusive. + // + + var editColTimer; + var editColAction; + // + // this is the target function of the interval timeout. + // check to see if the dialog is visible. if the dialog + // has gone invisible since the last check, take any delayed + // actions indicated in the action list and clear the timer. + // + + function checkVisible( ) { + editcol = document.getElementById( 'editcol' ); + if ( editcol.offsetWidth <= 0 ) { + clearInterval( editColTimer ); + editColTimer = false; + hideshowColumns( ); + editColAction = [ ]; + } + } function filterTableRows(test) { if (test.length > 0) { @@ -24,6 +49,113 @@ $('tr.data').show(); } } + + // + // determine the value of the indicated url arg. + // this is needed to determine whether a resort + // is necessary. it looks like a lot of gorp stuff + // but its actually pretty simple. + // + + function getURLParameter( name ) { + return decodeURIComponent((new RegExp('[?|&]' + name + '=' + + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, + '%20'))||null + } + + // + // when the dialog box goes invisible + // this function is called to interpret + // the action list and take any delayed actions necessary. + // the editColAction list is a hash table with + // the column name as the hash key, the hash value + // is a 2 element list. the first element is a flag + // indicating whether the column is on or off. the + // 2nd element is the sort order indicator for the column. + // + + function hideshowColumns( ) { + for( var k in editColAction ) { + showhideDelayedTableAction( k, editColAction[ k ][ 0 ], editColAction[ k ][ 1 ]); + } + } + + // + // this function actually performs the delayed table actions + // namely any resorting if necessary + // + + function showhideDelayedTableAction( clname, sh, orderkey ) { + if ( !sh ) { + p = getURLParameter( "orderby" ).split( ":" )[ 0 ]; + if ( p == orderkey ) { + reload_params({ 'orderby' : '{{default_orderby}}'}); + } + } + } + + // + // this function actually performs the immediate table actions + // namely any colums that need to be hidden/shown + // + + function showhideImmediateTableAction( clname, sh, orderkey ) { + if ( sh ) { + $( '.' + clname ).show( 100 ); + } + else { + $( '.' + clname ).hide( 100 ); + } + + // save cookie for all checkboxes + save = ''; + $( '.chbxtoggle' ).each(function( ) { + if ( $( this ).attr( 'id' ) != undefined ) { + save += ';' + $( this ).attr( 'id' ) +':'+ $( this ).is( ':checked' ) + } + }); + $.cookie( '_displaycols_{{objectname}}', save ); + save = ''; + } + + // + // this is the onclick handler for all of the check box + // items in edit columns dialog + // + + function showhideTableColumn( clname, sh, orderkey ) { + editcol = document.getElementById( 'editcol' ); + if ( editcol.offsetWidth <= 0 ) { + + // + // this path is taken when the page is first + // getting initialized - no dialog visible, + // perform both the immediate and delayed actions + // + + showhideImmediateTableAction( clname, sh, orderkey ); + showhideDelayedTableAction( clname, sh, orderkey ); + return; + } + if ( !editColTimer ) { + + // + // we don't have a timer active so set one up + // and clear the action list + // + + editColTimer = setInterval( checkVisible, 250 ); + editColAction = [ ]; + } + + // + // save the action to be taken when the dialog closes + // + + editColAction[ clname ] = [ sh, orderkey ]; + showhideImmediateTableAction( clname, sh, orderkey ); + } + </script> <!-- control header --> @@ -33,7 +165,6 @@ <input class="input-xxlarge" id="search" name="search" type="text" placeholder="Search {%if object_search_display %}{{object_search_display}}{%else%}{{objectname}}{%endif%}" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{%endif%} <input type="hidden" name="orderby" value="{{request.GET.orderby}}"> <input type="hidden" name="page" value="1"> - <input type="hidden" name="count" value="{{request.GET.count}}"> <button class="btn" type="submit" value="Search">Search</button> </form> <div class="pull-right"> @@ -45,12 +176,27 @@ <!-- {{tablecols|sortcols}} --> - <ul class="dropdown-menu">{% for i in tablecols|sortcols %} + <ul id='editcol' class="dropdown-menu"> + {% for i in tablecols|sortcols %} <li> <label {% if not i.clclass %} class="checkbox muted" {%else%} class="checkbox" {%endif%}> - <input type="checkbox" class="chbxtoggle" {% if i.clclass %}id="{{i.clclass}}" value="ct{{i.name}}" {% if not i.hidden %}checked="checked"{%endif%} onchange="showhideTableColumn($(this).attr('id'), $(this).is(':checked'))" {%else%} checked disabled {% endif %}/> {{i.name}} + <input type="checkbox" class="chbxtoggle" + {% if i.clclass %} + id="{{i.clclass}}" + value="ct{{i.name}}" + {% if not i.hidden %} + checked="checked" + {%endif%} + onclick="showhideTableColumn( + $(this).attr('id'), + $(this).is(':checked'), + '{{i.orderkey}}' )" + {%else%} + checked disabled + {% endif %}/> {{i.name}} </label> - </li>{% endfor %} + </li> + {% endfor %} </ul> </div> {% endif %} diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index e3b24ba..4622810 100644 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py @@ -262,6 +262,7 @@ def builds(request): # TODO: common objects for all table views, adapt as needed 'objects' : build_info, 'objectname' : "builds", + 'default_orderby' : 'completed_on:-', 'fstypes' : fstypes_map, 'search_term' : search_term, 'total_count' : queryset_with_search.count(), @@ -311,6 +312,7 @@ def builds(request): 'qhelp': "The date and time the build finished", 'orderfield': _get_toggle_order(request, "completed_on", True), 'ordericon':_get_toggle_order_icon(request, "completed_on"), + 'orderkey' : 'completed_on', 'filter' : {'class' : 'completed_on', 'label': 'Show:', 'options' : [ @@ -334,6 +336,7 @@ def builds(request): 'qhelp': "How many errors were encountered during the build (if any)", 'orderfield': _get_toggle_order(request, "errors_no", True), 'ordericon':_get_toggle_order_icon(request, "errors_no"), + 'orderkey' : 'errors_no', 'filter' : {'class' : 'errors_no', 'label': 'Show:', 'options' : [ @@ -346,6 +349,7 @@ def builds(request): 'qhelp': "How many warnings were encountered during the build (if any)", 'orderfield': _get_toggle_order(request, "warnings_no", True), 'ordericon':_get_toggle_order_icon(request, "warnings_no"), + 'orderkey' : 'warnings_no', 'filter' : {'class' : 'warnings_no', 'label': 'Show:', 'options' : [ @@ -358,6 +362,7 @@ def builds(request): 'qhelp': "How long it took the build to finish", 'orderfield': _get_toggle_order(request, "timespent", True), 'ordericon':_get_toggle_order_icon(request, "timespent"), + 'orderkey' : 'timespent', }, {'name': 'Log', 'dclass': "span4", @@ -365,6 +370,7 @@ def builds(request): 'clclass': 'log', 'hidden': 1, 'orderfield': _get_toggle_order(request, "cooker_log_path"), 'ordericon':_get_toggle_order_icon(request, "cooker_log_path"), + 'orderkey' : 'cooker_log_path', }, {'name': 'Output', 'clclass': 'output', 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory", @@ -502,7 +508,7 @@ def task( request, build_id, task_id ): 'log_head' : log_head, 'log_body' : log_body, 'showing_matches' : False, - 'uri_list' : uri_list, + 'uri_list' : uri_list, } if request.GET.get( 'show_matches', "" ): context[ 'showing_matches' ] = True @@ -559,6 +565,7 @@ def target(request, build_id, target_id): 'objects': packages, 'packages_sum' : packages_sum['installed_size__sum'], 'object_search_display': "packages included", + 'default_orderby' : 'name:+', 'tablecols':[ { 'name':'Package', @@ -575,6 +582,7 @@ def target(request, build_id, target_id): 'qhelp':'The size of the package', 'orderfield': _get_toggle_order(request, "size", True), 'ordericon':_get_toggle_order_icon(request, "size"), + 'orderkey' : 'size', 'clclass': 'size', 'dclass' : 'span2', 'hidden' : 0, @@ -582,6 +590,7 @@ def target(request, build_id, target_id): { 'name':'Size over total (%)', 'qhelp':'Proportion of the overall included package size represented by this package', + 'orderkey' : 'size', 'clclass': 'size_over_total', 'dclass' : 'span2', 'hidden' : 1, @@ -591,6 +600,7 @@ def target(request, build_id, target_id): 'qhelp':'The license under which the package is distributed. Multiple license names separated by the pipe character indicates a choice between licenses. Multiple license names separated by the ampersand character indicates multiple licenses exist that cover different parts of the source', 'orderfield': _get_toggle_order(request, "license"), 'ordericon':_get_toggle_order_icon(request, "license"), + 'orderkey' : 'license', 'clclass': 'license', 'hidden' : 1, }, @@ -611,6 +621,7 @@ def target(request, build_id, target_id): 'qhelp':'The name of the recipe building the package', 'orderfield': _get_toggle_order(request, "recipe__name"), 'ordericon':_get_toggle_order_icon(request, "recipe__name"), + 'orderkey' : 'recipe__name', 'clclass': 'recipe_name', 'hidden' : 0, }, @@ -625,6 +636,7 @@ def target(request, build_id, target_id): 'qhelp':'The name of the layer providing the recipe that builds the package', 'orderfield': _get_toggle_order(request, "recipe__layer_version__layer__name"), 'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__layer__name"), + 'orderkey' : 'recipe__layer_version__layer__name', 'clclass': 'layer_name', 'hidden' : 1, }, @@ -633,6 +645,7 @@ def target(request, build_id, target_id): 'qhelp':'The Git branch of the layer providing the recipe that builds the package', 'orderfield': _get_toggle_order(request, "recipe__layer_version__branch"), 'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__branch"), + 'orderkey' : 'recipe__layer_version__branch', 'clclass': 'layer_branch', 'hidden' : 1, }, @@ -830,21 +843,25 @@ def tasks_common(request, build_id, variant, task_anchor): object_search_display="time data" filter_search_display="tasks" mandatory_parameters = { 'count': 25, 'page' : 1, 'orderby':'elapsed_time:-'}; + default_orderby = 'elapsed_time:-'; elif 'diskio' == variant: title_variant='Disk I/O' object_search_display="disk I/O data" filter_search_display="tasks" mandatory_parameters = { 'count': 25, 'page' : 1, 'orderby':'disk_io:-'}; + default_orderby = 'disk_io:-'; elif 'cpuusage' == variant: title_variant='CPU usage' object_search_display="CPU usage data" filter_search_display="tasks" mandatory_parameters = { 'count': 25, 'page' : 1, 'orderby':'cpu_usage:-'}; + default_orderby = 'cpu_usage:-'; else : title_variant='Tasks' object_search_display="tasks" filter_search_display="tasks" mandatory_parameters = { 'count': 25, 'page' : 1, 'orderby':'order:+'}; + default_orderby = 'order:+'; template = 'tasks.html' retval = _verify_parameters( request.GET, mandatory_parameters ) @@ -886,12 +903,14 @@ def tasks_common(request, build_id, variant, task_anchor): 'name':'Order', 'qhelp':'The running sequence of each task in the build', 'clclass': 'order', 'hidden' : 1, + 'orderkey' : 'order', 'orderfield':_get_toggle_order(request, "order"), 'ordericon':_get_toggle_order_icon(request, "order")} if 'tasks' == variant: tc_order['hidden']='0'; del tc_order['clclass'] tc_recipe={ 'name':'Recipe', 'qhelp':'The name of the recipe to which each task applies', + 'orderkey' : 'recipe__name', 'orderfield': _get_toggle_order(request, "recipe__name"), 'ordericon':_get_toggle_order_icon(request, "recipe__name"), } @@ -905,6 +924,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'qhelp':'The name of the task', 'orderfield': _get_toggle_order(request, "task_name"), 'ordericon':_get_toggle_order_icon(request, "task_name"), + 'orderkey' : 'task_name', } tc_executed={ 'name':'Executed', @@ -912,6 +932,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'clclass': 'executed', 'hidden' : 0, 'orderfield': _get_toggle_order(request, "task_executed"), 'ordericon':_get_toggle_order_icon(request, "task_executed"), + 'orderkey' : 'task_executed', 'filter' : { 'class' : 'executed', 'label': 'Show:', @@ -928,6 +949,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'clclass': 'outcome', 'hidden' : 0, 'orderfield': _get_toggle_order(request, "outcome"), 'ordericon':_get_toggle_order_icon(request, "outcome"), + 'orderkey' : 'outcome', 'filter' : { 'class' : 'outcome', 'label': 'Show:', @@ -947,6 +969,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'qhelp':'Path to the task log file', 'orderfield': _get_toggle_order(request, "logfile"), 'ordericon':_get_toggle_order_icon(request, "logfile"), + 'orderkey' : 'logfile', 'clclass': 'task_log', 'hidden' : 1, } tc_cache={ @@ -955,6 +978,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'clclass': 'cache_attempt', 'hidden' : 0, 'orderfield': _get_toggle_order(request, "sstate_result"), 'ordericon':_get_toggle_order_icon(request, "sstate_result"), + 'orderkey' : 'sstate_result', 'filter' : { 'class' : 'cache_attempt', 'label': 'Show:', @@ -973,6 +997,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'qhelp':'How long it took the task to finish in seconds', 'orderfield': _get_toggle_order(request, "elapsed_time", True), 'ordericon':_get_toggle_order_icon(request, "elapsed_time"), + 'orderkey' : 'elapsed_time', 'clclass': 'time_taken', 'hidden' : 1, } if 'buildtime' == variant: tc_time['hidden']='0'; del tc_time['clclass']; tc_cache['hidden']='1'; @@ -981,6 +1006,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'qhelp':'The percentage of task CPU utilization', 'orderfield': _get_toggle_order(request, "cpu_usage", True), 'ordericon':_get_toggle_order_icon(request, "cpu_usage"), + 'orderkey' : 'cpu_usage', 'clclass': 'cpu_used', 'hidden' : 1, } if 'cpuusage' == variant: tc_cpu['hidden']='0'; del tc_cpu['clclass']; tc_cache['hidden']='1'; @@ -989,6 +1015,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'qhelp':'Number of miliseconds the task spent doing disk input and output', 'orderfield': _get_toggle_order(request, "disk_io", True), 'ordericon':_get_toggle_order_icon(request, "disk_io"), + 'orderkey' : 'disk_io', 'clclass': 'disk_io', 'hidden' : 1, } if 'diskio' == variant: tc_diskio['hidden']='0'; del tc_diskio['clclass']; tc_cache['hidden']='1'; @@ -1000,6 +1027,7 @@ def tasks_common(request, build_id, variant, task_anchor): 'title': title_variant, 'build': Build.objects.filter(pk=build_id)[0], 'objects': tasks, + 'default_orderby' : default_orderby, 'search_term': search_term, 'total_count': queryset_with_search.count(), 'tablecols':[ @@ -1050,6 +1078,7 @@ def recipes(request, build_id): 'objectname': 'recipes', 'build': Build.objects.filter(pk=build_id)[0], 'objects': recipes, + 'default_orderby' : 'name:+', 'tablecols':[ { 'name':'Recipe', @@ -1076,6 +1105,7 @@ def recipes(request, build_id): 'qhelp':'Path to the recipe .bb file', 'orderfield': _get_toggle_order(request, "file_path"), 'ordericon':_get_toggle_order_icon(request, "file_path"), + 'orderkey' : 'file_path', 'clclass': 'recipe_file', 'hidden': 0, }, { @@ -1083,6 +1113,7 @@ def recipes(request, build_id): 'qhelp':'The section in which recipes should be categorized', 'orderfield': _get_toggle_order(request, "section"), 'ordericon':_get_toggle_order_icon(request, "section"), + 'orderkey' : 'section', 'clclass': 'recipe_section', 'hidden': 0, }, { @@ -1090,6 +1121,7 @@ def recipes(request, build_id): 'qhelp':'The list of source licenses for the recipe. Multiple license names separated by the pipe character indicates a choice between licenses. Multiple license names separated by the ampersand character indicates multiple licenses exist that cover different parts of the source', 'orderfield': _get_toggle_order(request, "license"), 'ordericon':_get_toggle_order_icon(request, "license"), + 'orderkey' : 'license', 'clclass': 'recipe_license', 'hidden': 0, }, { @@ -1097,6 +1129,7 @@ def recipes(request, build_id): 'qhelp':'The name of the layer providing the recipe', 'orderfield': _get_toggle_order(request, "layer_version__layer__name"), 'ordericon':_get_toggle_order_icon(request, "layer_version__layer__name"), + 'orderkey' : 'layer_version__layer__name', 'clclass': 'layer_version__layer__name', 'hidden': 0, }, { @@ -1104,6 +1137,7 @@ def recipes(request, build_id): 'qhelp':'The Git branch of the layer providing the recipe', 'orderfield': _get_toggle_order(request, "layer_version__branch"), 'ordericon':_get_toggle_order_icon(request, "layer_version__branch"), + 'orderkey' : 'layer_version__branch', 'clclass': 'layer_version__branch', 'hidden': 1, }, { @@ -1116,6 +1150,7 @@ def recipes(request, build_id): 'qhelp':'Path to the layer prodiving the recipe', 'orderfield': _get_toggle_order(request, "layer_version__layer__local_path"), 'ordericon':_get_toggle_order_icon(request, "layer_version__layer__local_path"), + 'orderkey' : 'layer_version__layer__local_path', 'clclass': 'layer_version__layer__local_path', 'hidden': 1, }, ] @@ -1198,6 +1233,7 @@ def configvars(request, build_id): 'build': Build.objects.filter(pk=build_id)[0], 'objects' : variables, 'total_count':queryset_with_search.count(), + 'default_orderby' : 'variable_name:+', 'search_term':search_term, # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns 'tablecols' : [ @@ -1213,6 +1249,7 @@ def configvars(request, build_id): {'name': 'Set in file', 'qhelp': "The last configuration file that touched the variable value", 'clclass': 'file', 'hidden' : 0, + 'orderkey' : 'vhistory__file_name', 'filter' : { 'class' : 'vhistory__file_name', 'label': 'Show:', @@ -1259,6 +1296,7 @@ def bpackage(request, build_id): 'objectname': 'packages built', 'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages, + 'default_orderby' : 'name:+', 'tablecols':[ { 'name':'Package', @@ -1275,6 +1313,7 @@ def bpackage(request, build_id): 'qhelp':'The size of the package', 'orderfield': _get_toggle_order(request, "size", True), 'ordericon':_get_toggle_order_icon(request, "size"), + 'orderkey' : 'size', 'clclass': 'size', 'hidden': 0, 'dclass' : 'span2', }, @@ -1283,6 +1322,7 @@ def bpackage(request, build_id): 'qhelp':'The license under which the package is distributed. Multiple license names separated by the pipe character indicates a choice between licenses. Multiple license names separated by the ampersand character indicates multiple licenses exist that cover different parts of the source', 'orderfield': _get_toggle_order(request, "license"), 'ordericon':_get_toggle_order_icon(request, "license"), + 'orderkey' : 'license', 'clclass': 'license', 'hidden': 1, }, { @@ -1290,6 +1330,7 @@ def bpackage(request, build_id): 'qhelp':'The name of the recipe building the package', 'orderfield': _get_toggle_order(request, "recipe__name"), 'ordericon':_get_toggle_order_icon(request, "recipe__name"), + 'orderkey' : 'recipe__name', 'clclass': 'recipe__name', 'hidden': 0, }, { @@ -1302,6 +1343,7 @@ def bpackage(request, build_id): 'qhelp':'The name of the layer providing the recipe that builds the package', 'orderfield': _get_toggle_order(request, "recipe__layer_version__layer__name"), 'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__layer__name"), + 'orderkey' : 'recipe__layer_version__layer__name', 'clclass': 'recipe__layer_version__layer__name', 'hidden': 1, }, { @@ -1309,6 +1351,7 @@ def bpackage(request, build_id): 'qhelp':'The Git branch of the layer providing the recipe that builds the package', 'orderfield': _get_toggle_order(request, "recipe__layer_version__branch"), 'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__branch"), + 'orderkey' : 'recipe__layer_version__layer__branch', 'clclass': 'recipe__layer_version__branch', 'hidden': 1, }, { @@ -1321,6 +1364,7 @@ def bpackage(request, build_id): 'qhelp':'Path to the layer providing the recipe that builds the package', 'orderfield': _get_toggle_order(request, "recipe__layer_version__layer__local_path"), 'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__layer__local_path"), + 'orderkey' : 'recipe__layer_version__layer__local_path', 'clclass': 'recipe__layer_version__layer__local_path', 'hidden': 1, }, ] |