Fossil SCM

Add a timeline view at the top of the /tktview page if the "tl" query parameter is present. If a ticket is viewed from /info, then the timeline is always on. Perhaps the timeline should be on regardless?

drh 2019-12-23 12:26 trunk
Commit 3d131528c8c0167d6d1d06cd161e752d6c2ae53d03e56909635f4ab6259a6162
2 files changed +1 +57 -32
+1
--- src/info.c
+++ src/info.c
@@ -2511,10 +2511,11 @@
25112511
}
25122512
rc = name_to_uuid(&uuid, -1, "*");
25132513
if( rc==1 ){
25142514
if( validate16(zName, nLen) ){
25152515
if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
2516
+ cgi_set_parameter_nocopy("tl","1",0);
25162517
tktview_page();
25172518
return;
25182519
}
25192520
if( db_exists("SELECT 1 FROM tag"
25202521
" WHERE tagname GLOB 'event-%q*'", zName) ){
25212522
--- src/info.c
+++ src/info.c
@@ -2511,10 +2511,11 @@
2511 }
2512 rc = name_to_uuid(&uuid, -1, "*");
2513 if( rc==1 ){
2514 if( validate16(zName, nLen) ){
2515 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
 
2516 tktview_page();
2517 return;
2518 }
2519 if( db_exists("SELECT 1 FROM tag"
2520 " WHERE tagname GLOB 'event-%q*'", zName) ){
2521
--- src/info.c
+++ src/info.c
@@ -2511,10 +2511,11 @@
2511 }
2512 rc = name_to_uuid(&uuid, -1, "*");
2513 if( rc==1 ){
2514 if( validate16(zName, nLen) ){
2515 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
2516 cgi_set_parameter_nocopy("tl","1",0);
2517 tktview_page();
2518 return;
2519 }
2520 if( db_exists("SELECT 1 FROM tag"
2521 " WHERE tagname GLOB 'event-%q*'", zName) ){
2522
+57 -32
--- src/tkt.c
+++ src/tkt.c
@@ -445,27 +445,30 @@
445445
@ </ul></div>
446446
}
447447
448448
/*
449449
** WEBPAGE: tktview
450
-** URL: tktview?name=UUID
450
+** URL: tktview?name=HASH
451451
**
452452
** View a ticket identified by the name= query parameter.
453
+** Other query parameters:
454
+**
455
+** tl Show a timeline of the ticket above the status
453456
*/
454457
void tktview_page(void){
455458
const char *zScript;
456459
char *zFullName;
457460
const char *zUuid = PD("name","");
461
+ int showTimeline = P("tl")!=0;
458462
459463
login_check_credentials();
460464
if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
461465
if( g.anon.WrTkt || g.anon.ApndTkt ){
462466
style_submenu_element("Edit", "%s/tktedit?name=%T", g.zTop, PD("name",""));
463467
}
464468
if( g.perm.Hyperlink ){
465469
style_submenu_element("History", "%s/tkthistory/%T", g.zTop, zUuid);
466
- style_submenu_element("Timeline", "%s/tkttimeline/%T", g.zTop, zUuid);
467470
style_submenu_element("Check-ins", "%s/tkttimeline/%T?y=ci", g.zTop, zUuid);
468471
}
469472
if( g.anon.NewTkt ){
470473
style_submenu_element("New Ticket", "%s/tktnew", g.zTop);
471474
}
@@ -477,10 +480,23 @@
477480
style_submenu_element("Formatted", "%R/tktview/%s", zUuid);
478481
}else{
479482
style_submenu_element("Plaintext", "%R/tktview/%s?plaintext", zUuid);
480483
}
481484
style_header("View Ticket");
485
+ if( showTimeline ){
486
+ int tagid = db_int(0,"SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
487
+ zUuid);
488
+ if( tagid ){
489
+ tkt_draw_timeline(tagid, "a");
490
+ @ <hr>
491
+ }else{
492
+ showTimeline = 0;
493
+ }
494
+ }
495
+ if( !showTimeline && g.perm.Hyperlink ){
496
+ style_submenu_element("Timeline", "%s/info/%T", g.zTop, zUuid);
497
+ }
482498
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
483499
ticket_init();
484500
initializeVariablesFromCGI();
485501
getAllTicketFields();
486502
initializeVariablesFromDb();
@@ -825,23 +841,58 @@
825841
}
826842
sqlite3_close(db);
827843
}
828844
return zErr;
829845
}
846
+
847
+/*
848
+** Draw a timeline for a ticket with tag.tagid given by the tagid
849
+** parameter.
850
+*/
851
+void tkt_draw_timeline(int tagid, const char *zType){
852
+ Stmt q;
853
+ char *zFullUuid;
854
+ char *zSQL;
855
+ zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
856
+ tagid);
857
+ if( zType[0]=='c' ){
858
+ zSQL = mprintf(
859
+ "%s AND event.objid IN "
860
+ " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
861
+ "AND '%s' GLOB (target||'*')) "
862
+ "ORDER BY mtime DESC",
863
+ timeline_query_for_www(), zFullUuid, zFullUuid
864
+ );
865
+ }else{
866
+ zSQL = mprintf(
867
+ "%s AND event.objid IN "
868
+ " (SELECT rid FROM tagxref WHERE tagid=%d"
869
+ " UNION SELECT srcid FROM backlink"
870
+ " WHERE target GLOB '%.4s*'"
871
+ " AND '%s' GLOB (target||'*')"
872
+ " UNION SELECT attachid FROM attachment"
873
+ " WHERE target=%Q) "
874
+ "ORDER BY mtime DESC",
875
+ timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid
876
+ );
877
+ }
878
+ db_prepare(&q, "%z", zSQL/*safe-for-%s*/);
879
+ www_print_timeline(&q, TIMELINE_ARTID|TIMELINE_DISJOINT|TIMELINE_GRAPH,
880
+ 0, 0, 0, 0, 0, 0);
881
+ db_finalize(&q);
882
+ fossil_free(zFullUuid);
883
+}
830884
831885
/*
832886
** WEBPAGE: tkttimeline
833887
** URL: /tkttimeline?name=TICKETUUID&y=TYPE
834888
**
835889
** Show the change history for a single ticket in timeline format.
836890
*/
837891
void tkttimeline_page(void){
838
- Stmt q;
839892
char *zTitle;
840
- char *zSQL;
841893
const char *zUuid;
842
- char *zFullUuid;
843894
int tagid;
844895
char zGlobPattern[50];
845896
const char *zType;
846897
847898
login_check_credentials();
@@ -872,37 +923,11 @@
872923
if( tagid==0 ){
873924
@ No such ticket: %h(zUuid)
874925
style_footer();
875926
return;
876927
}
877
- zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
878
- tagid);
879
- if( zType[0]=='c' ){
880
- zSQL = mprintf(
881
- "%s AND event.objid IN "
882
- " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
883
- "AND '%s' GLOB (target||'*')) "
884
- "ORDER BY mtime DESC",
885
- timeline_query_for_www(), zFullUuid, zFullUuid
886
- );
887
- }else{
888
- zSQL = mprintf(
889
- "%s AND event.objid IN "
890
- " (SELECT rid FROM tagxref WHERE tagid=%d"
891
- " UNION SELECT srcid FROM backlink"
892
- " WHERE target GLOB '%.4s*'"
893
- " AND '%s' GLOB (target||'*')"
894
- " UNION SELECT attachid FROM attachment"
895
- " WHERE target=%Q) "
896
- "ORDER BY mtime DESC",
897
- timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid
898
- );
899
- }
900
- db_prepare(&q, "%z", zSQL/*safe-for-%s*/);
901
- www_print_timeline(&q, TIMELINE_ARTID|TIMELINE_DISJOINT|TIMELINE_GRAPH,
902
- 0, 0, 0, 0, 0, 0);
903
- db_finalize(&q);
928
+ tkt_draw_timeline(tagid, zType);
904929
style_footer();
905930
}
906931
907932
/*
908933
** WEBPAGE: tkthistory
909934
--- src/tkt.c
+++ src/tkt.c
@@ -445,27 +445,30 @@
445 @ </ul></div>
446 }
447
448 /*
449 ** WEBPAGE: tktview
450 ** URL: tktview?name=UUID
451 **
452 ** View a ticket identified by the name= query parameter.
 
 
 
453 */
454 void tktview_page(void){
455 const char *zScript;
456 char *zFullName;
457 const char *zUuid = PD("name","");
 
458
459 login_check_credentials();
460 if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
461 if( g.anon.WrTkt || g.anon.ApndTkt ){
462 style_submenu_element("Edit", "%s/tktedit?name=%T", g.zTop, PD("name",""));
463 }
464 if( g.perm.Hyperlink ){
465 style_submenu_element("History", "%s/tkthistory/%T", g.zTop, zUuid);
466 style_submenu_element("Timeline", "%s/tkttimeline/%T", g.zTop, zUuid);
467 style_submenu_element("Check-ins", "%s/tkttimeline/%T?y=ci", g.zTop, zUuid);
468 }
469 if( g.anon.NewTkt ){
470 style_submenu_element("New Ticket", "%s/tktnew", g.zTop);
471 }
@@ -477,10 +480,23 @@
477 style_submenu_element("Formatted", "%R/tktview/%s", zUuid);
478 }else{
479 style_submenu_element("Plaintext", "%R/tktview/%s?plaintext", zUuid);
480 }
481 style_header("View Ticket");
 
 
 
 
 
 
 
 
 
 
 
 
 
482 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
483 ticket_init();
484 initializeVariablesFromCGI();
485 getAllTicketFields();
486 initializeVariablesFromDb();
@@ -825,23 +841,58 @@
825 }
826 sqlite3_close(db);
827 }
828 return zErr;
829 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
830
831 /*
832 ** WEBPAGE: tkttimeline
833 ** URL: /tkttimeline?name=TICKETUUID&y=TYPE
834 **
835 ** Show the change history for a single ticket in timeline format.
836 */
837 void tkttimeline_page(void){
838 Stmt q;
839 char *zTitle;
840 char *zSQL;
841 const char *zUuid;
842 char *zFullUuid;
843 int tagid;
844 char zGlobPattern[50];
845 const char *zType;
846
847 login_check_credentials();
@@ -872,37 +923,11 @@
872 if( tagid==0 ){
873 @ No such ticket: %h(zUuid)
874 style_footer();
875 return;
876 }
877 zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
878 tagid);
879 if( zType[0]=='c' ){
880 zSQL = mprintf(
881 "%s AND event.objid IN "
882 " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
883 "AND '%s' GLOB (target||'*')) "
884 "ORDER BY mtime DESC",
885 timeline_query_for_www(), zFullUuid, zFullUuid
886 );
887 }else{
888 zSQL = mprintf(
889 "%s AND event.objid IN "
890 " (SELECT rid FROM tagxref WHERE tagid=%d"
891 " UNION SELECT srcid FROM backlink"
892 " WHERE target GLOB '%.4s*'"
893 " AND '%s' GLOB (target||'*')"
894 " UNION SELECT attachid FROM attachment"
895 " WHERE target=%Q) "
896 "ORDER BY mtime DESC",
897 timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid
898 );
899 }
900 db_prepare(&q, "%z", zSQL/*safe-for-%s*/);
901 www_print_timeline(&q, TIMELINE_ARTID|TIMELINE_DISJOINT|TIMELINE_GRAPH,
902 0, 0, 0, 0, 0, 0);
903 db_finalize(&q);
904 style_footer();
905 }
906
907 /*
908 ** WEBPAGE: tkthistory
909
--- src/tkt.c
+++ src/tkt.c
@@ -445,27 +445,30 @@
445 @ </ul></div>
446 }
447
448 /*
449 ** WEBPAGE: tktview
450 ** URL: tktview?name=HASH
451 **
452 ** View a ticket identified by the name= query parameter.
453 ** Other query parameters:
454 **
455 ** tl Show a timeline of the ticket above the status
456 */
457 void tktview_page(void){
458 const char *zScript;
459 char *zFullName;
460 const char *zUuid = PD("name","");
461 int showTimeline = P("tl")!=0;
462
463 login_check_credentials();
464 if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
465 if( g.anon.WrTkt || g.anon.ApndTkt ){
466 style_submenu_element("Edit", "%s/tktedit?name=%T", g.zTop, PD("name",""));
467 }
468 if( g.perm.Hyperlink ){
469 style_submenu_element("History", "%s/tkthistory/%T", g.zTop, zUuid);
 
470 style_submenu_element("Check-ins", "%s/tkttimeline/%T?y=ci", g.zTop, zUuid);
471 }
472 if( g.anon.NewTkt ){
473 style_submenu_element("New Ticket", "%s/tktnew", g.zTop);
474 }
@@ -477,10 +480,23 @@
480 style_submenu_element("Formatted", "%R/tktview/%s", zUuid);
481 }else{
482 style_submenu_element("Plaintext", "%R/tktview/%s?plaintext", zUuid);
483 }
484 style_header("View Ticket");
485 if( showTimeline ){
486 int tagid = db_int(0,"SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
487 zUuid);
488 if( tagid ){
489 tkt_draw_timeline(tagid, "a");
490 @ <hr>
491 }else{
492 showTimeline = 0;
493 }
494 }
495 if( !showTimeline && g.perm.Hyperlink ){
496 style_submenu_element("Timeline", "%s/info/%T", g.zTop, zUuid);
497 }
498 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
499 ticket_init();
500 initializeVariablesFromCGI();
501 getAllTicketFields();
502 initializeVariablesFromDb();
@@ -825,23 +841,58 @@
841 }
842 sqlite3_close(db);
843 }
844 return zErr;
845 }
846
847 /*
848 ** Draw a timeline for a ticket with tag.tagid given by the tagid
849 ** parameter.
850 */
851 void tkt_draw_timeline(int tagid, const char *zType){
852 Stmt q;
853 char *zFullUuid;
854 char *zSQL;
855 zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
856 tagid);
857 if( zType[0]=='c' ){
858 zSQL = mprintf(
859 "%s AND event.objid IN "
860 " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
861 "AND '%s' GLOB (target||'*')) "
862 "ORDER BY mtime DESC",
863 timeline_query_for_www(), zFullUuid, zFullUuid
864 );
865 }else{
866 zSQL = mprintf(
867 "%s AND event.objid IN "
868 " (SELECT rid FROM tagxref WHERE tagid=%d"
869 " UNION SELECT srcid FROM backlink"
870 " WHERE target GLOB '%.4s*'"
871 " AND '%s' GLOB (target||'*')"
872 " UNION SELECT attachid FROM attachment"
873 " WHERE target=%Q) "
874 "ORDER BY mtime DESC",
875 timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid
876 );
877 }
878 db_prepare(&q, "%z", zSQL/*safe-for-%s*/);
879 www_print_timeline(&q, TIMELINE_ARTID|TIMELINE_DISJOINT|TIMELINE_GRAPH,
880 0, 0, 0, 0, 0, 0);
881 db_finalize(&q);
882 fossil_free(zFullUuid);
883 }
884
885 /*
886 ** WEBPAGE: tkttimeline
887 ** URL: /tkttimeline?name=TICKETUUID&y=TYPE
888 **
889 ** Show the change history for a single ticket in timeline format.
890 */
891 void tkttimeline_page(void){
 
892 char *zTitle;
 
893 const char *zUuid;
 
894 int tagid;
895 char zGlobPattern[50];
896 const char *zType;
897
898 login_check_credentials();
@@ -872,37 +923,11 @@
923 if( tagid==0 ){
924 @ No such ticket: %h(zUuid)
925 style_footer();
926 return;
927 }
928 tkt_draw_timeline(tagid, zType);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
929 style_footer();
930 }
931
932 /*
933 ** WEBPAGE: tkthistory
934

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button