Fossil

Check-in [965905c884]
Login

Check-in [965905c884]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhance the /brlist output to show a count of the number of check-ins on each branch, and to separate the "Status" and "Resolution" into separate columns, with the "Status" column being sortable. Enhance the SortableTable() javascript to always sort ASC on initial click and only go to DESC on a second click of the same column.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 965905c884286e466c3494b3b15d10a1a902cd16
User & Date: drh 2015-01-04 20:54:00.599
Context
2015-01-05
01:57
Change the cursor to "pointer" for sortable columns of a table. ... (check-in: 54d53deb16 user: drh tags: trunk)
2015-01-04
20:54
Enhance the /brlist output to show a count of the number of check-ins on each branch, and to separate the "Status" and "Resolution" into separate columns, with the "Status" column being sortable. Enhance the SortableTable() javascript to always sort ASC on initial click and only go to DESC on a second click of the same column. ... (check-in: 965905c884 user: drh tags: trunk)
00:28
Click on the column labels to sort on the /brlist page. ... (check-in: e35b9cb74c user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/branch.c.
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320


321
322
323
324
325
326
327
328
329
330
331
332
333
}

static char brlistQuery[] = 
@ SELECT
@   tagxref.value,
@   max(event.mtime),
@   EXISTS(SELECT 1 FROM tagxref AS tx
@           WHERE tx.rid=leaf.rid
@             AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed')
@             AND tx.tagtype>0),
@   (SELECT tagxref.value
@      FROM plink CROSS JOIN tagxref
@    WHERE plink.pid=leaf.rid
@       AND tagxref.rid=plink.cid
@      AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch')
@      AND tagtype>0)


@  FROM leaf, tagxref, tag, event
@ WHERE leaf.rid=tagxref.rid
@   AND tagxref.tagid=tag.tagid
@   AND tagxref.tagtype>0
@   AND tag.tagname='branch'
@   AND event.objid=leaf.rid
@ GROUP BY 1
@ ORDER BY %d DESC;
;

/*
** This is the new-style branch-list page that shows the branch names
** together with their ages (time of last check-in) and whether or not







|




|


|
>
>
|
<
|


|







305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323

324
325
326
327
328
329
330
331
332
333
334
}

static char brlistQuery[] = 
@ SELECT
@   tagxref.value,
@   max(event.mtime),
@   EXISTS(SELECT 1 FROM tagxref AS tx
@           WHERE tx.rid=tagxref.rid
@             AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed')
@             AND tx.tagtype>0),
@   (SELECT tagxref.value
@      FROM plink CROSS JOIN tagxref
@    WHERE plink.pid=event.objid
@       AND tagxref.rid=plink.cid
@      AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch')
@      AND tagtype>0),
@   count(*),
@   (SELECT uuid FROM blob WHERE rid=tagxref.rid)
@  FROM tagxref, tag, event

@ WHERE tagxref.tagid=tag.tagid
@   AND tagxref.tagtype>0
@   AND tag.tagname='branch'
@   AND event.objid=tagxref.rid
@ GROUP BY 1
@ ORDER BY %d DESC;
;

/*
** This is the new-style branch-list page that shows the branch names
** together with their ages (time of last check-in) and whether or not
348
349
350
351
352
353
354

355

356
357
358
359
360
361


362
363
364
365
366
367

368

369
370
371
372

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  assert( orderByMtime==0 || orderByMtime==1 );
  db_prepare(&q, brlistQuery/*works-like:"%d"*/, 2-orderByMtime);
  rNow = db_double(0.0, "SELECT julianday('now')");
  @ <div class="brlist"><table id="branchlisttable">
  @ <thead><tr>
  @ <th>Branch Name</th>
  @ <th>Age</th>

  @ <th>Status</th>

  @ </tr></thead><tbody>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zBranch = db_column_text(&q, 0);
    double rMtime = db_column_double(&q, 1);
    int isClosed = db_column_int(&q, 2);
    const char *zMergeTo = db_column_text(&q, 3);


    char *zAge = human_readable_age(rNow - rMtime);
    sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0);
    if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0;
    @ <tr>
    @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a>
    @ <td data-sortkey="%016llx(iMtime)">%s(zAge)

    fossil_free(zAge);

    if( isClosed && zMergeTo ){
      @ <td>closed,
    }else if( isClosed ){
      @ <td>closed

    }else{
      @ <td>
    }
    if( zMergeTo ){
      @ merged into %z(href("%R/timeline?r=%T",zMergeTo))%h(zMergeTo)</a>
    }
    @ </tr>
  }
  @ </tbody></table></div>
  db_finalize(&q);
  output_table_sorting_javascript("branchlisttable","tkx");
  style_footer();
}

/*
** WEBPAGE: brlist
** Show a list of branches
** Query parameters:







>

>






>
>




|
|
>

>
|
<
<
|
>

|
<
<
<





|







349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376


377
378
379
380



381
382
383
384
385
386
387
388
389
390
391
392
393
  assert( orderByMtime==0 || orderByMtime==1 );
  db_prepare(&q, brlistQuery/*works-like:"%d"*/, 2-orderByMtime);
  rNow = db_double(0.0, "SELECT julianday('now')");
  @ <div class="brlist"><table id="branchlisttable">
  @ <thead><tr>
  @ <th>Branch Name</th>
  @ <th>Age</th>
  @ <th>Checkins</th>
  @ <th>Status</th>
  @ <th>Resolution</th>
  @ </tr></thead><tbody>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zBranch = db_column_text(&q, 0);
    double rMtime = db_column_double(&q, 1);
    int isClosed = db_column_int(&q, 2);
    const char *zMergeTo = db_column_text(&q, 3);
    int nCkin = db_column_int(&q, 4);
    const char *zLastCkin = db_column_text(&q, 5);
    char *zAge = human_readable_age(rNow - rMtime);
    sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0);
    if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0;
    @ <tr>
    @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td>
    @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td>
    @ <td data-sortkey="%08x(-nCkin)">%d(nCkin)</td>
    fossil_free(zAge);
    @ <td>%s(isClosed?"closed":"")</td>
    if( zMergeTo ){


      @ <td>merged into
      @ %z(href("%R/timeline?f=%s",zLastCkin))%h(zMergeTo)</a></td>
    }else{
      @ <td></td>



    }
    @ </tr>
  }
  @ </tbody></table></div>
  db_finalize(&q);
  output_table_sorting_javascript("branchlisttable","tkktx");
  style_footer();
}

/*
** WEBPAGE: brlist
** Show a list of branches
** Query parameters:
Changes to src/report.c.
926
927
928
929
930
931
932


933



934
935


936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960

961
962
963
964
965
966
967
**
** The javascript is derived from:
**
**     http://www.webtoolkit.info/sortable-html-table.html
**
** This variation allows column types to be expressed using the second
** argument.  Each character of the second argument represent a column.


** "t" means sort as text.  "n" means sort numerically.  "x" means do not



** sort on this column.  If there are fewer characters in zColumnTypes[] than
** their are columns, the all extra columns assume type "t" (text).


*/
void output_table_sorting_javascript(const char *zTableId, const char *zColumnTypes){
  @ <script>
  @ function SortableTable(tableEl,columnTypes){
  @   this.tbody = tableEl.getElementsByTagName('tbody');
  @   this.sort = function (cell) {
  @     var column = cell.cellIndex;
  @     var sortFn;
  @     switch( cell.sortType ){
  @       case "n":  sortFn = this.sortNumeric;  break;
  @       case "t":  sortFn = this.sortText;     break;
  @       case "k":  sortFn = this.sortKey;      break;
  @       case "x":  return;
  @     }
  @     this.sortIndex = column;
  @     var newRows = new Array();
  @     for (j = 0; j < this.tbody[0].rows.length; j++) {
  @        newRows[j] = this.tbody[0].rows[j];
  @     }
  @     newRows.sort(sortFn);
  @     if (cell.getAttribute("sortdir") == 'down') {
  @        newRows.reverse();
  @        cell.setAttribute('sortdir','up');
  @     } else {
  @        cell.setAttribute('sortdir','down');

  @     }
  @     for (i=0;i<newRows.length;i++) {
  @       this.tbody[0].appendChild(newRows[i]);
  @     }
  @   }
  @   this.sortText = function(a,b) {
  @     var i = thisObject.sortIndex;







>
>
|
>
>
>
|
|
>
>



















|
<
|
<
|
|
>







926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962

963

964
965
966
967
968
969
970
971
972
973
**
** The javascript is derived from:
**
**     http://www.webtoolkit.info/sortable-html-table.html
**
** This variation allows column types to be expressed using the second
** argument.  Each character of the second argument represent a column.
**
**       t      Sort by text
**       n      Sort numerically
**       k      Sort by the data-sortkey property
**       x      This column is not sortable
**
** If there are fewer characters in zColumnTypes[] than their are columns,
** the all extra columns assume type "t" (text).
**
** Clicking on the same column header twice in a row inverts the sort.
*/
void output_table_sorting_javascript(const char *zTableId, const char *zColumnTypes){
  @ <script>
  @ function SortableTable(tableEl,columnTypes){
  @   this.tbody = tableEl.getElementsByTagName('tbody');
  @   this.sort = function (cell) {
  @     var column = cell.cellIndex;
  @     var sortFn;
  @     switch( cell.sortType ){
  @       case "n":  sortFn = this.sortNumeric;  break;
  @       case "t":  sortFn = this.sortText;     break;
  @       case "k":  sortFn = this.sortKey;      break;
  @       case "x":  return;
  @     }
  @     this.sortIndex = column;
  @     var newRows = new Array();
  @     for (j = 0; j < this.tbody[0].rows.length; j++) {
  @        newRows[j] = this.tbody[0].rows[j];
  @     }
  @     if( this.sortIndex==this.prevColumn ){

  @       newRows.reverse();

  @     }else{
  @       newRows.sort(sortFn);
  @       this.prevColumn = this.sortIndex;
  @     }
  @     for (i=0;i<newRows.length;i++) {
  @       this.tbody[0].appendChild(newRows[i]);
  @     }
  @   }
  @   this.sortText = function(a,b) {
  @     var i = thisObject.sortIndex;
984
985
986
987
988
989
990

991
992
993
994
995
996
997
  @     aa = a.cells[i].getAttribute("data-sortkey");
  @     bb = b.cells[i].getAttribute("data-sortkey");
  @     if(aa==bb) return 0;
  @     if(aa<bb) return -1;
  @     return 1;
  @   }
  @   var thisObject = this;

  @   var x = tableEl.getElementsByTagName('thead');
  @   if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
  @     return;
  @   }
  @   if(x && x[0].rows && x[0].rows.length > 0) {
  @     var sortRow = x[0].rows[0];
  @   } else {







>







990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  @     aa = a.cells[i].getAttribute("data-sortkey");
  @     bb = b.cells[i].getAttribute("data-sortkey");
  @     if(aa==bb) return 0;
  @     if(aa<bb) return -1;
  @     return 1;
  @   }
  @   var thisObject = this;
  @   var prevColumn = -1;
  @   var x = tableEl.getElementsByTagName('thead');
  @   if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
  @     return;
  @   }
  @   if(x && x[0].rows && x[0].rows.length > 0) {
  @     var sortRow = x[0].rows[0];
  @   } else {
Changes to src/style.c.
1273
1274
1275
1276
1277
1278
1279

1280
1281
1282
1283
1284
1285
1286
    @ max-width: 50%;
  },
  { ".brlist table",  "The list of branches",
    @ border-spacing: 0;
  },
  { ".brlist table th",  "Branch list table headers",
    @ text-align: left;

  },
  { ".brlist table td",  "Branch list table headers",
    @ padding: 0px 2em 0px 0px;
  },
  { 0,
    0,
    0







>







1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
    @ max-width: 50%;
  },
  { ".brlist table",  "The list of branches",
    @ border-spacing: 0;
  },
  { ".brlist table th",  "Branch list table headers",
    @ text-align: left;
    @ padding: 0px 1em 0.5ex 0px;
  },
  { ".brlist table td",  "Branch list table headers",
    @ padding: 0px 2em 0px 0px;
  },
  { 0,
    0,
    0