Fossil

Check-in [a6a44820]
Login

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

Overview
Comment:Begin work merging new_brlist_page() into brlist_page().

Annoyance: The new open/closed checkboxes don't quite work the way I want them to work. Deselecting both has the effect of selecting both. This makes sense in that if neither the open nor closed query parameters are given, everything should be displayed, rather than nothing. Yet, the user interface would be nicer if deselecting the only selected checkbox causes the other checkbox to be selected. This can't be done with straight HTML because deselecting the checkbox removes it from the query string, and the server does not know which checkbox was deselected so it cannot force the other one to become selected. As far as I know, JavaScript is required.

Bug: Non-aggregate HAVING clause expressions are evaluated on an arbitrarily chosen row within each group. This breaks closed and open filtering for the command-line branch command and the new checkboxes. But shouldn't this also break non-aggregate result expressions?

Wish: Filter on normal/hidden branches too.

Wish: If a merged-to branch is hidden, don't show it in the resolution column, instead show something else. The latest merged-to? The earliest merged-to?

Wish: Branch name filters, just like on the timeline page.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | andygoth-branch-list
Files: files | file ages | folders
SHA1:a6a4482056851df4b3d194d1b524d6e252e92df0
User & Date: andygoth 2016-11-16 21:59:09
Original Comment: Begin work merging new_brlist_page() into brlist_page().

Annoyance: The new open/closed checkboxes don't quite work the way I want them to work. Deselecting both has the effect of selecting both. This makes sense in that if neither the open nor closed query parameters are given, everything should be displayed, rather than nothing. Yet, the user interface would be nicer if deselecting the only selected checkbox causes the other checkbox to be selected. This can't be done with straight HTML because deselecting the checkbox removes it from the query string, and the server does not know which checkbox was deselected so it cannot force the other one to become selected. As far as I know, JavaScript is required.

Bug: Non-aggregate HAVING clause expressions are evaluated on an arbitrarily chosen row within each group. This breaks closed and open filtering for the command-line branch command and the new checkboxes. But shouldn't this also break non-aggregate result expressions?

Wish: Filter on normal/hidden branches too.

Wish: If a merged-to branch is hidden, don't show it in the resolution column, instead show something else. The latest merged-to? The earliest merged-to?

Context
2016-11-18
21:45
Remove min() from closed expression. It doesn't solve the problem, and it confuses analysis of the issue. check-in: 4e7d2ce1 user: andygoth tags: andygoth-branch-list
2016-11-16
21:59
Begin work merging new_brlist_page() into brlist_page().

Annoyance: The new open/closed checkboxes don't quite work the way I want them to work. Deselecting both has the effect of selecting both. This makes sense in that if neither the open nor closed query parameters are given, everything should be displayed, rather than nothing. Yet, the user interface would be nicer if deselecting the only selected checkbox causes the other checkbox to be selected. This can't be done with straight HTML because deselecting the checkbox removes it from the query string, and the server does not know which checkbox was deselected so it cannot force the other one to become selected. As far as I know, JavaScript is required.

Bug: Non-aggregate HAVING clause expressions are evaluated on an arbitrarily chosen row within each group. This breaks closed and open filtering for the command-line branch command and the new checkboxes. But shouldn't this also break non-aggregate result expressions?

Wish: Filter on normal/hidden branches too.

Wish: If a merged-to branch is hidden, don't show it in the resolution column, instead show something else. The latest merged-to? The earliest merged-to?

Wish: Branch name filters, just like on the timeline page. check-in: a6a44820 user: andygoth tags: andygoth-branch-list

19:29
Enable linenoise multiline editing so long commands and queries may be seen all at once therefore highlighted and copied from xterms check-in: 03b68698 user: andygoth tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/branch.c.

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243


244
245
246
247
248
249
250
...
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
335
336
337
338
339
340
341


342
343
344





345
346
347
348






























349



350
351
352
353
354




355
356
357

358
359
360
361
362
363

364

365
366
367
368
369
370
371
...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393

394

395
396
397
398
399
400
401
...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
/*
** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
*/
#define BRL_CLOSED_ONLY      0x001 /* Show only closed branches */
#define BRL_OPEN_ONLY        0x002 /* Show only open branches */
#define BRL_BOTH             0x003 /* Show both open and closed branches */
#define BRL_OPEN_CLOSED_MASK 0x003
#define BRL_MTIME            0x004 /* Include lastest check-in time */
#define BRL_ORDERBY_MTIME    0x008 /* Sort by MTIME. (otherwise sort by name)*/

#endif /* INTERFACE */

/*
** Prepare a query that will list branches.
**
** If (which<0) then the query pulls only closed branches. If
** (which>0) then the query pulls all (closed and opened)
** branches. Else the query pulls currently-opened branches.
*/
void branch_prepare_list_query(Stmt *pQuery, int brFlags){
  switch( brFlags & BRL_OPEN_CLOSED_MASK ){
    case BRL_CLOSED_ONLY: {
      db_prepare(pQuery,
        "SELECT value FROM tagxref"
        " WHERE tagid=%d AND value NOT NULL "
        "EXCEPT "
        "SELECT value FROM tagxref"
        " WHERE tagid=%d"
        "   AND rid IN leaf"
        "   AND NOT %z"
        " ORDER BY value COLLATE nocase /*sort*/",
        TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
      );
      break;
    }
    case BRL_BOTH: {
      db_prepare(pQuery,
        "SELECT DISTINCT value FROM tagxref"
        " WHERE tagid=%d AND value NOT NULL"
        "   AND rid IN leaf"
        " ORDER BY value COLLATE nocase /*sort*/",
        TAG_BRANCH
      );
      break;
    }
    case BRL_OPEN_ONLY: {
      db_prepare(pQuery,
        "SELECT DISTINCT value FROM tagxref"
        " WHERE tagid=%d AND value NOT NULL"
        "   AND rid IN leaf"
        "   AND NOT %z"
        " ORDER BY value COLLATE nocase /*sort*/",
        TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
      );
      break;
    }
  }
}




/*
** COMMAND: branch
**
** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS?
**
** Run various subcommands to manage branches of the open repository or
................................................................................
    db_finalize(&q);
  }else{
    fossil_fatal("branch subcommand should be one of: "
                 "new list ls");
  }
}

static const 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),
@   event.bgcolor
@  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 2 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
** they are closed or merged to another branch.


**
** Control jumps to this routine from brlist_page() (the /brlist handler)
** if there are no query parameters.





*/
static void new_brlist_page(void){
  Stmt q;
  double rNow;






























  int show_colors = PB("colors");



  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_header("Branches");
  style_adunit_config(ADUNIT_RIGHT_OK);
  style_submenu_checkbox("colors", "Use Branch Colors", 0);




  login_anonymous_available();

  db_prepare(&q, brlistQuery/*works-like:""*/);

  rNow = db_double(0.0, "SELECT julianday('now')");
  @ <div class="brlist"><table id="branchlisttable">
  @ <thead><tr>
  @ <th>Branch Name</th>
  @ <th>Age</th>
  @ <th>Check-ins</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);
................................................................................
    if( zBgClr == 0 ){
      if( zBranch==0 || strcmp(zBranch,"trunk")==0 ){
        zBgClr = 0;
      }else{
        zBgClr = hash_color(zBranch);
      }
    }
    if( zBgClr && zBgClr[0] && show_colors ){
      @ <tr style="background-color:%s(zBgClr)">
    }else{
      @ <tr>
    }
    @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td>
    @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td>
    @ <td>%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","tkNtt",2);
  style_footer();
}

/*
** WEBPAGE: brlist
** Show a list of branches.  With no query parameters, a sortable table
** is used to show all branches.  If query parameters are present a
** fixed bullet list is shown.
**
** Query parameters:
**
**     all         Show all branches
**     closed      Show only closed branches
**     open        Show only open branches (default behavior)
**     colortest   Show all branches with automatic color
*/
void brlist_page(void){
  Stmt q;
  int cnt;
  int showClosed = P("closed")!=0;
  int showAll = P("all")!=0;
  int showOpen = P("open")!=0;
  int colorTest = P("colortest")!=0;
  int brFlags = BRL_OPEN_ONLY;

  if( showClosed==0 && showAll==0 && showOpen==0 && colorTest==0 ){
    new_brlist_page();
    return;
  }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  if( colorTest ){
    showClosed = 0;
    showAll = 1;
  }
  if( showAll ) brFlags = BRL_BOTH;
  if( showClosed ) brFlags = BRL_CLOSED_ONLY;

  style_header("%s", showClosed ? "Closed Branches" :
                        showAll ? "All Branches" : "Open Branches");
  style_submenu_element("Timeline", "brtimeline");
  if( showClosed ){
    style_submenu_element("All", "brlist?all");
    style_submenu_element("Open", "brlist?open");
  }else if( showAll ){
    style_submenu_element("Closed", "brlist?closed");
    style_submenu_element("Open", "brlist");
  }else{
    style_submenu_element("All", "brlist?all");
    style_submenu_element("Closed", "brlist?closed");
  }
  if( !colorTest ){
    style_submenu_element("Color-Test", "brlist?colortest");
  }else{
    style_submenu_element("All", "brlist?all");
  }
  login_anonymous_available();
#if 0
  style_sidebox_begin("Nomenclature:", "33%");
  @ <ol>
  @ <li> An <div class="sideboxDescribed">%z(href("brlist"))
  @ open branch</a></div> is a branch that has one or more
  @ <div class="sideboxDescribed">%z(href("leaves"))open leaves.</a></div>
  @ The presence of open leaves presumably means
  @ that the branch is still being extended with new check-ins.</li>
  @ <li> A <div class="sideboxDescribed">%z(href("brlist?closed"))
  @ closed branch</a></div> is a branch with only
  @ <div class="sideboxDescribed">%z(href("leaves?closed"))
  @ closed leaves</a></div>.
  @ Closed branches are fixed and do not change (unless they are first
  @ reopened).</li>
  @ </ol>
  style_sidebox_end();
#endif

  branch_prepare_list_query(&q, brFlags);
  cnt = 0;
  while( db_step(&q)==SQLITE_ROW ){
    const char *zBr = db_column_text(&q, 0);
    if( cnt==0 ){
      if( colorTest ){
        @ <h2>Default background colors for all branches:</h2>
      }else if( showClosed ){
        @ <h2>Closed Branches:</h2>
      }else if( showAll ){
        @ <h2>All Branches:</h2>
      }else{
        @ <h2>Open Branches:</h2>
      }
      @ <ul>
      cnt++;
    }
    if( colorTest ){
      const char *zColor = hash_color(zBr);
      @ <li><span style="background-color: %s(zColor)">
      @ %h(zBr) &rarr; %s(zColor)</span></li>
    }else{
      @ <li>%z(href("%R/timeline?r=%T&n=200",zBr))%h(zBr)</a></li>
    }
  }
  if( cnt ){
    @ </ul>
  }
  db_finalize(&q);
  style_footer();
}

/*
** This routine is called while for each check-in that is rendered by
** the timeline of a "brlist" page.  Add some additional hyperlinks
** to the end of the line.
*/
static void brtimeline_extra(int rid){
  Stmt q;







<
|





|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
>
>

<
|
>
>
>
>
>

|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>




|
>
>
>
>


<
>






>

>







 







|








>
|
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







185
186
187
188
189
190
191

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
...
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
335
336
337
338
339
340
341
342
343
344
345
346
347
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
...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
...
421
422
423
424
425
426
427








































































































428
429
430
431
432
433
434
/*
** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
*/
#define BRL_CLOSED_ONLY      0x001 /* Show only closed branches */
#define BRL_OPEN_ONLY        0x002 /* Show only open branches */
#define BRL_BOTH             0x003 /* Show both open and closed branches */
#define BRL_OPEN_CLOSED_MASK 0x003

#define BRL_ORDERBY_MTIME    0x004 /* Sort by MTIME. (otherwise sort by name)*/

#endif /* INTERFACE */

/*
** Prepare a query that will list branches.
*/
void branch_prepare_list_query(Stmt *pQuery, int brFlags){
  Blob sql = BLOB_INITIALIZER;
  blob_zero(&sql);

  /* Begin the query. */
  blob_append_sql(&sql,
    "SELECT tagxref.value AS name"
         ", max(event.mtime) AS mtime"
         ", %z AS closed"
         ", (SELECT tagxref.value"
             " FROM plink CROSS JOIN tagxref"
            " WHERE plink.pid=event.objid"
              " AND tagxref.rid=plink.cid"
              " AND tagxref.tagid=%d"
              " AND tagtype>0) AS mergeto"
         ", count(*) AS cicount"
         ", (SELECT uuid FROM blob WHERE rid=tagxref.rid) AS latest"
         ", event.bgcolor AS bgcolor"
     " FROM tagxref, tag, event"
    " WHERE tagxref.tagid=tag.tagid"
      " AND tagxref.tagtype>0"
      " AND tag.tagname='branch'"
      " AND event.objid=tagxref.rid",
    leaf_is_closed_sql("tagxref.rid"), TAG_BRANCH);

  /* Group by name to implement the cicount column. */
  blob_append_sql(&sql, " GROUP BY name");

  /* Apply open/closed filtering if requested. */
  if( (brFlags & BRL_OPEN_CLOSED_MASK)==BRL_CLOSED_ONLY ){
    blob_append_sql(&sql, " HAVING min(closed)");
  }else if( (brFlags & BRL_OPEN_CLOSED_MASK)==BRL_OPEN_ONLY ){
    blob_append_sql(&sql, " HAVING NOT min(closed)");
  }

  /* Apply the requested sort order. */
  if( brFlags & BRL_ORDERBY_MTIME ){
    blob_append_sql(&sql, " ORDER BY mtime DESC");
  }else{
    blob_append_sql(&sql, " ORDER BY name COLLATE nocase");
  }

  /* Prepare the query. */
  db_prepare(pQuery, "%s", blob_sql_text(&sql));
  blob_reset(&sql);
}

/*
** COMMAND: branch
**
** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS?
**
** Run various subcommands to manage branches of the open repository or
................................................................................
    db_finalize(&q);
  }else{
    fossil_fatal("branch subcommand should be one of: "
                 "new list ls");
  }
}



























/*



** WEBPAGE: brlist
** Show a sortable list of branches.
**

** Query parameters:
**
**     all         Same as open&closed
**     open        Show open branches
**     closed      Show closed branches
**     colors      Show assigned branch colors (alias: colortest)
*/
void brlist_page(void){
  Stmt q;
  double rNow;
  int colors, flags = BRL_ORDERBY_MTIME;

  /* Intepret colortest as colors=1. */
  if( PB("colortest") ){
    cgi_replace_query_parameter("colors", "1");
  }
  cgi_delete_query_parameter("colortest");

  /* Interpret all as open=1&closed=1&normal=1&hidden=1. */
  if( PB("all") ){
    cgi_replace_query_parameter("open", "1");
    cgi_replace_query_parameter("closed", "1");
/*  cgi_replace_query_parameter("normal", "1");
    cgi_replace_query_parameter("hidden", "1");*/
  }
  cgi_delete_query_parameter("all");

  /* Interpret open=0&closed=0 (or omitted) as open=1&closed=1. */
  if( !PB("open") && !PB("closed") ){
    cgi_replace_query_parameter("open", "1");
    cgi_replace_query_parameter("closed", "1");
  }

  /* Interpret normal=0&hidden=0 (or omitted) as normal=1&hidden=1. */
/*if( !PB("normal") && !PB("hidden") ){
    cgi_replace_query_parameter("normal", "1");
    cgi_replace_query_parameter("hidden", "1");
  }*/

  /* Process query parameters. */
  colors = PB("colors");
  if( PB("open"  ) ){flags |= BRL_OPEN_ONLY  ;}
  if( PB("closed") ){flags |= BRL_CLOSED_ONLY;}

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_header("Branches");
  style_adunit_config(ADUNIT_RIGHT_OK);
  style_submenu_checkbox("colors", "Colors", 0);
  style_submenu_checkbox("open", "Open", 0);
  style_submenu_checkbox("closed", "Closed", 0);
/*style_submenu_checkbox("normal", "Normal", 0);
  style_submenu_checkbox("hidden", "Hidden", 0);*/
  login_anonymous_available();


  branch_prepare_list_query(&q, flags);
  rNow = db_double(0.0, "SELECT julianday('now')");
  @ <div class="brlist"><table id="branchlisttable">
  @ <thead><tr>
  @ <th>Branch Name</th>
  @ <th>Age</th>
  @ <th>Check-ins</th>
  if( (flags & BRL_OPEN_CLOSED_MASK) == BRL_BOTH ){
  @ <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);
................................................................................
    if( zBgClr == 0 ){
      if( zBranch==0 || strcmp(zBranch,"trunk")==0 ){
        zBgClr = 0;
      }else{
        zBgClr = hash_color(zBranch);
      }
    }
    if( zBgClr && zBgClr[0] && colors ){
      @ <tr style="background-color:%s(zBgClr)">
    }else{
      @ <tr>
    }
    @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td>
    @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td>
    @ <td>%d(nCkin)</td>
    fossil_free(zAge);
    if( (flags & BRL_OPEN_CLOSED_MASK) == BRL_BOTH ){
      @ <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","tkNtt",2);
  style_footer();
}









































































































/*
** This routine is called while for each check-in that is rendered by
** the timeline of a "brlist" page.  Add some additional hyperlinks
** to the end of the line.
*/
static void brtimeline_extra(int rid){
  Stmt q;