Fossil SCM
Add the "circa" capability to the timeline. Check-in hyperlinks go to the "diff" page by default, rather than the "detail" page.
Commit
5a539f82dc57e0a6794def3d1cbc367c71668efd
Parent
5b91887495c357f…
2 files changed
+24
-8
+34
-2
+24
-8
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -425,11 +425,11 @@ | ||
| 425 | 425 | } |
| 426 | 426 | db_finalize(&q); |
| 427 | 427 | @ </td></tr> |
| 428 | 428 | @ <tr><th>Commands:</th> |
| 429 | 429 | @ <td> |
| 430 | - @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a> | |
| 430 | + @ <a href="%s(g.zBaseURL)/vdiff/%s(zShortUuid)">diff</a> | |
| 431 | 431 | @ | <a href="%s(g.zBaseURL)/dir?ci=%s(zShortUuid)">files</a> |
| 432 | 432 | @ | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)"> |
| 433 | 433 | @ ZIP archive</a> |
| 434 | 434 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 435 | 435 | if( g.okWrite ){ |
| @@ -671,10 +671,11 @@ | ||
| 671 | 671 | @ %h(blob_str(&out)) |
| 672 | 672 | blob_reset(&from); |
| 673 | 673 | blob_reset(&to); |
| 674 | 674 | blob_reset(&out); |
| 675 | 675 | } |
| 676 | + | |
| 676 | 677 | |
| 677 | 678 | /* |
| 678 | 679 | ** WEBPAGE: vdiff |
| 679 | 680 | ** URL: /vdiff?name=RID |
| 680 | 681 | ** |
| @@ -685,29 +686,44 @@ | ||
| 685 | 686 | Stmt q; |
| 686 | 687 | char *zUuid; |
| 687 | 688 | |
| 688 | 689 | login_check_credentials(); |
| 689 | 690 | if( !g.okRead ){ login_needed(); return; } |
| 690 | - style_header("Check-in Changes"); | |
| 691 | 691 | login_anonymous_available(); |
| 692 | 692 | |
| 693 | 693 | rid = name_to_rid(PD("name","")); |
| 694 | 694 | if( rid==0 ){ |
| 695 | 695 | fossil_redirect_home(); |
| 696 | 696 | } |
| 697 | + zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 698 | + style_header("Check-in [%.10s]", zUuid); | |
| 699 | + db_prepare(&q, | |
| 700 | + "SELECT datetime(mtime), " | |
| 701 | + " coalesce(event.ecomment,event.comment)," | |
| 702 | + " coalesce(event.euser,event.user)" | |
| 703 | + " FROM event WHERE type='ci' AND objid=%d", | |
| 704 | + rid | |
| 705 | + ); | |
| 706 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 707 | + const char *zDate = db_column_text(&q, 0); | |
| 708 | + const char *zUser = db_column_text(&q, 2); | |
| 709 | + const char *zComment = db_column_text(&q, 1); | |
| 710 | + @ <h2>Check-in %s(zUuid)</h2> | |
| 711 | + @ <p>Made by %h(zUser) on | |
| 712 | + link_to_date(zDate, ":"); | |
| 713 | + @ %w(zComment). <a href="%s(g.zBaseURL)/ci/%s(zUuid)">[details]</a></p> | |
| 714 | + @ <hr> | |
| 715 | + } | |
| 716 | + db_finalize(&q); | |
| 697 | 717 | db_prepare(&q, |
| 698 | 718 | "SELECT pid, fid, name" |
| 699 | 719 | " FROM mlink, filename" |
| 700 | 720 | " WHERE mlink.mid=%d" |
| 701 | 721 | " AND filename.fnid=mlink.fnid" |
| 702 | 722 | " ORDER BY name", |
| 703 | 723 | rid |
| 704 | 724 | ); |
| 705 | - zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 706 | - @ <h2>All Changes In Check-in | |
| 707 | - hyperlink_to_uuid(zUuid); | |
| 708 | - @ </h2> | |
| 709 | 725 | while( db_step(&q)==SQLITE_ROW ){ |
| 710 | 726 | int pid = db_column_int(&q,0); |
| 711 | 727 | int fid = db_column_int(&q,1); |
| 712 | 728 | const char *zName = db_column_text(&q,2); |
| 713 | 729 | @ <p><a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></p> |
| @@ -716,11 +732,10 @@ | ||
| 716 | 732 | @ </pre></blockquote> |
| 717 | 733 | } |
| 718 | 734 | db_finalize(&q); |
| 719 | 735 | style_footer(); |
| 720 | 736 | } |
| 721 | - | |
| 722 | 737 | |
| 723 | 738 | /* |
| 724 | 739 | ** Write a description of an object to the www reply. |
| 725 | 740 | ** |
| 726 | 741 | ** If the object is a file then mention: |
| @@ -851,10 +866,11 @@ | ||
| 851 | 866 | } |
| 852 | 867 | }else if( linkToView ){ |
| 853 | 868 | @ <a href="%s(g.zBaseURL)/artifact/%d(rid)">[view]</a> |
| 854 | 869 | } |
| 855 | 870 | } |
| 871 | + | |
| 856 | 872 | |
| 857 | 873 | /* |
| 858 | 874 | ** WEBPAGE: fdiff |
| 859 | 875 | ** |
| 860 | 876 | ** Two arguments, v1 and v2, are integers. Show the difference between |
| @@ -1192,11 +1208,11 @@ | ||
| 1192 | 1208 | @ <p>No such object: %h(zName)</p> |
| 1193 | 1209 | style_footer(); |
| 1194 | 1210 | return; |
| 1195 | 1211 | } |
| 1196 | 1212 | if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ |
| 1197 | - ci_page(); | |
| 1213 | + vdiff_page(); | |
| 1198 | 1214 | }else |
| 1199 | 1215 | if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" |
| 1200 | 1216 | " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){ |
| 1201 | 1217 | winfo_page(); |
| 1202 | 1218 | }else |
| 1203 | 1219 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -425,11 +425,11 @@ | |
| 425 | } |
| 426 | db_finalize(&q); |
| 427 | @ </td></tr> |
| 428 | @ <tr><th>Commands:</th> |
| 429 | @ <td> |
| 430 | @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a> |
| 431 | @ | <a href="%s(g.zBaseURL)/dir?ci=%s(zShortUuid)">files</a> |
| 432 | @ | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)"> |
| 433 | @ ZIP archive</a> |
| 434 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 435 | if( g.okWrite ){ |
| @@ -671,10 +671,11 @@ | |
| 671 | @ %h(blob_str(&out)) |
| 672 | blob_reset(&from); |
| 673 | blob_reset(&to); |
| 674 | blob_reset(&out); |
| 675 | } |
| 676 | |
| 677 | /* |
| 678 | ** WEBPAGE: vdiff |
| 679 | ** URL: /vdiff?name=RID |
| 680 | ** |
| @@ -685,29 +686,44 @@ | |
| 685 | Stmt q; |
| 686 | char *zUuid; |
| 687 | |
| 688 | login_check_credentials(); |
| 689 | if( !g.okRead ){ login_needed(); return; } |
| 690 | style_header("Check-in Changes"); |
| 691 | login_anonymous_available(); |
| 692 | |
| 693 | rid = name_to_rid(PD("name","")); |
| 694 | if( rid==0 ){ |
| 695 | fossil_redirect_home(); |
| 696 | } |
| 697 | db_prepare(&q, |
| 698 | "SELECT pid, fid, name" |
| 699 | " FROM mlink, filename" |
| 700 | " WHERE mlink.mid=%d" |
| 701 | " AND filename.fnid=mlink.fnid" |
| 702 | " ORDER BY name", |
| 703 | rid |
| 704 | ); |
| 705 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 706 | @ <h2>All Changes In Check-in |
| 707 | hyperlink_to_uuid(zUuid); |
| 708 | @ </h2> |
| 709 | while( db_step(&q)==SQLITE_ROW ){ |
| 710 | int pid = db_column_int(&q,0); |
| 711 | int fid = db_column_int(&q,1); |
| 712 | const char *zName = db_column_text(&q,2); |
| 713 | @ <p><a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></p> |
| @@ -716,11 +732,10 @@ | |
| 716 | @ </pre></blockquote> |
| 717 | } |
| 718 | db_finalize(&q); |
| 719 | style_footer(); |
| 720 | } |
| 721 | |
| 722 | |
| 723 | /* |
| 724 | ** Write a description of an object to the www reply. |
| 725 | ** |
| 726 | ** If the object is a file then mention: |
| @@ -851,10 +866,11 @@ | |
| 851 | } |
| 852 | }else if( linkToView ){ |
| 853 | @ <a href="%s(g.zBaseURL)/artifact/%d(rid)">[view]</a> |
| 854 | } |
| 855 | } |
| 856 | |
| 857 | /* |
| 858 | ** WEBPAGE: fdiff |
| 859 | ** |
| 860 | ** Two arguments, v1 and v2, are integers. Show the difference between |
| @@ -1192,11 +1208,11 @@ | |
| 1192 | @ <p>No such object: %h(zName)</p> |
| 1193 | style_footer(); |
| 1194 | return; |
| 1195 | } |
| 1196 | if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ |
| 1197 | ci_page(); |
| 1198 | }else |
| 1199 | if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" |
| 1200 | " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){ |
| 1201 | winfo_page(); |
| 1202 | }else |
| 1203 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -425,11 +425,11 @@ | |
| 425 | } |
| 426 | db_finalize(&q); |
| 427 | @ </td></tr> |
| 428 | @ <tr><th>Commands:</th> |
| 429 | @ <td> |
| 430 | @ <a href="%s(g.zBaseURL)/vdiff/%s(zShortUuid)">diff</a> |
| 431 | @ | <a href="%s(g.zBaseURL)/dir?ci=%s(zShortUuid)">files</a> |
| 432 | @ | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)"> |
| 433 | @ ZIP archive</a> |
| 434 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 435 | if( g.okWrite ){ |
| @@ -671,10 +671,11 @@ | |
| 671 | @ %h(blob_str(&out)) |
| 672 | blob_reset(&from); |
| 673 | blob_reset(&to); |
| 674 | blob_reset(&out); |
| 675 | } |
| 676 | |
| 677 | |
| 678 | /* |
| 679 | ** WEBPAGE: vdiff |
| 680 | ** URL: /vdiff?name=RID |
| 681 | ** |
| @@ -685,29 +686,44 @@ | |
| 686 | Stmt q; |
| 687 | char *zUuid; |
| 688 | |
| 689 | login_check_credentials(); |
| 690 | if( !g.okRead ){ login_needed(); return; } |
| 691 | login_anonymous_available(); |
| 692 | |
| 693 | rid = name_to_rid(PD("name","")); |
| 694 | if( rid==0 ){ |
| 695 | fossil_redirect_home(); |
| 696 | } |
| 697 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 698 | style_header("Check-in [%.10s]", zUuid); |
| 699 | db_prepare(&q, |
| 700 | "SELECT datetime(mtime), " |
| 701 | " coalesce(event.ecomment,event.comment)," |
| 702 | " coalesce(event.euser,event.user)" |
| 703 | " FROM event WHERE type='ci' AND objid=%d", |
| 704 | rid |
| 705 | ); |
| 706 | while( db_step(&q)==SQLITE_ROW ){ |
| 707 | const char *zDate = db_column_text(&q, 0); |
| 708 | const char *zUser = db_column_text(&q, 2); |
| 709 | const char *zComment = db_column_text(&q, 1); |
| 710 | @ <h2>Check-in %s(zUuid)</h2> |
| 711 | @ <p>Made by %h(zUser) on |
| 712 | link_to_date(zDate, ":"); |
| 713 | @ %w(zComment). <a href="%s(g.zBaseURL)/ci/%s(zUuid)">[details]</a></p> |
| 714 | @ <hr> |
| 715 | } |
| 716 | db_finalize(&q); |
| 717 | db_prepare(&q, |
| 718 | "SELECT pid, fid, name" |
| 719 | " FROM mlink, filename" |
| 720 | " WHERE mlink.mid=%d" |
| 721 | " AND filename.fnid=mlink.fnid" |
| 722 | " ORDER BY name", |
| 723 | rid |
| 724 | ); |
| 725 | while( db_step(&q)==SQLITE_ROW ){ |
| 726 | int pid = db_column_int(&q,0); |
| 727 | int fid = db_column_int(&q,1); |
| 728 | const char *zName = db_column_text(&q,2); |
| 729 | @ <p><a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></p> |
| @@ -716,11 +732,10 @@ | |
| 732 | @ </pre></blockquote> |
| 733 | } |
| 734 | db_finalize(&q); |
| 735 | style_footer(); |
| 736 | } |
| 737 | |
| 738 | /* |
| 739 | ** Write a description of an object to the www reply. |
| 740 | ** |
| 741 | ** If the object is a file then mention: |
| @@ -851,10 +866,11 @@ | |
| 866 | } |
| 867 | }else if( linkToView ){ |
| 868 | @ <a href="%s(g.zBaseURL)/artifact/%d(rid)">[view]</a> |
| 869 | } |
| 870 | } |
| 871 | |
| 872 | |
| 873 | /* |
| 874 | ** WEBPAGE: fdiff |
| 875 | ** |
| 876 | ** Two arguments, v1 and v2, are integers. Show the difference between |
| @@ -1192,11 +1208,11 @@ | |
| 1208 | @ <p>No such object: %h(zName)</p> |
| 1209 | style_footer(); |
| 1210 | return; |
| 1211 | } |
| 1212 | if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ |
| 1213 | vdiff_page(); |
| 1214 | }else |
| 1215 | if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" |
| 1216 | " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){ |
| 1217 | winfo_page(); |
| 1218 | }else |
| 1219 |
+34
-2
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -54,11 +54,11 @@ | ||
| 54 | 54 | ){ |
| 55 | 55 | char zShortUuid[UUID_SIZE+1]; |
| 56 | 56 | sprintf(zShortUuid, "%.10s", zUuid); |
| 57 | 57 | if( g.okHistory ){ |
| 58 | 58 | @ <a onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")' |
| 59 | - @ href="%s(g.zBaseURL)/ci/%s(zUuid)">[%s(zShortUuid)]</a> | |
| 59 | + @ href="%s(g.zBaseURL)/vdiff/%s(zUuid)">[%s(zShortUuid)]</a> | |
| 60 | 60 | }else{ |
| 61 | 61 | @ <b onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")'> |
| 62 | 62 | @ [%s(zShortUuid)]</b> |
| 63 | 63 | } |
| 64 | 64 | } |
| @@ -308,10 +308,11 @@ | ||
| 308 | 308 | ** |
| 309 | 309 | ** Query parameters: |
| 310 | 310 | ** |
| 311 | 311 | ** a=TIMESTAMP after this date |
| 312 | 312 | ** b=TIMESTAMP before this date. |
| 313 | +** c=TIMESTAMP "circa" this date. | |
| 313 | 314 | ** n=COUNT number of events in output |
| 314 | 315 | ** p=RID artifact RID and up to COUNT parents and ancestors |
| 315 | 316 | ** d=RID artifact RID and up to COUNT descendants |
| 316 | 317 | ** t=TAGID show only check-ins with the given tagid |
| 317 | 318 | ** u=USER only if belonging to this user |
| @@ -334,10 +335,11 @@ | ||
| 334 | 335 | int d_rid = atoi(PD("d","0")); /* artifact d and its descendants */ |
| 335 | 336 | const char *zUser = P("u"); /* All entries by this user if not NULL */ |
| 336 | 337 | const char *zType = PD("y","all"); /* Type of events. All if NULL */ |
| 337 | 338 | const char *zAfter = P("a"); /* Events after this time */ |
| 338 | 339 | const char *zBefore = P("b"); /* Events before this time */ |
| 340 | + const char *zCirca = P("c"); /* Events near this time */ | |
| 339 | 341 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 340 | 342 | HQuery url; /* URL for various branch links */ |
| 341 | 343 | int tagid; /* Tag ID */ |
| 342 | 344 | |
| 343 | 345 | /* To view the timeline, must have permission to read project data. |
| @@ -442,10 +444,31 @@ | ||
| 442 | 444 | " ORDER BY event.mtime DESC", zBefore); |
| 443 | 445 | url_add_parameter(&url, "b", zBefore); |
| 444 | 446 | }else{ |
| 445 | 447 | zBefore = 0; |
| 446 | 448 | } |
| 449 | + }else if( zCirca ){ | |
| 450 | + while( isspace(zCirca[0]) ){ zCirca++; } | |
| 451 | + if( zCirca[0] ){ | |
| 452 | + double rCirca = db_double(0.0, "SELECT julianday(%Q, 'utc')", zCirca); | |
| 453 | + Blob sql2; | |
| 454 | + blob_init(&sql2, blob_str(&sql), -1); | |
| 455 | + blob_appendf(&sql2, | |
| 456 | + " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", | |
| 457 | + rCirca, (nEntry+1)/2 | |
| 458 | + ); | |
| 459 | + db_multi_exec("%s", blob_str(&sql2)); | |
| 460 | + blob_reset(&sql2); | |
| 461 | + blob_appendf(&sql, | |
| 462 | + " AND event.mtime>=%f ORDER BY event.mtime ASC", | |
| 463 | + rCirca | |
| 464 | + ); | |
| 465 | + nEntry -= (nEntry+1)/2; | |
| 466 | + url_add_parameter(&url, "c", zCirca); | |
| 467 | + }else{ | |
| 468 | + zCirca = 0; | |
| 469 | + } | |
| 447 | 470 | }else{ |
| 448 | 471 | blob_appendf(&sql, " ORDER BY event.mtime DESC"); |
| 449 | 472 | } |
| 450 | 473 | blob_appendf(&sql, " LIMIT %d", nEntry); |
| 451 | 474 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -452,11 +475,11 @@ | ||
| 452 | 475 | |
| 453 | 476 | n = db_int(0, "SELECT count(*) FROM timeline"); |
| 454 | 477 | if( n<nEntry && zAfter ){ |
| 455 | 478 | cgi_redirect(url_render(&url, "a", 0, "b", 0)); |
| 456 | 479 | } |
| 457 | - if( zAfter==0 && zBefore==0 ){ | |
| 480 | + if( zAfter==0 && zBefore==0 && zCirca==0 ){ | |
| 458 | 481 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 459 | 482 | }else{ |
| 460 | 483 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 461 | 484 | } |
| 462 | 485 | if( zUser ){ |
| @@ -467,10 +490,12 @@ | ||
| 467 | 490 | } |
| 468 | 491 | if( zAfter ){ |
| 469 | 492 | blob_appendf(&desc, " occurring on or after %h.<br>", zAfter); |
| 470 | 493 | }else if( zBefore ){ |
| 471 | 494 | blob_appendf(&desc, " occurring on or before %h.<br>", zBefore); |
| 495 | + }else if( zCirca ){ | |
| 496 | + blob_appendf(&desc, " occurring around %h.<br>", zCirca); | |
| 472 | 497 | } |
| 473 | 498 | if( g.okHistory ){ |
| 474 | 499 | if( zAfter || n==nEntry ){ |
| 475 | 500 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline"); |
| 476 | 501 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| @@ -601,10 +626,17 @@ | ||
| 601 | 626 | @ } |
| 602 | 627 | @ } |
| 603 | 628 | @ </script> |
| 604 | 629 | style_footer(); |
| 605 | 630 | } |
| 631 | + | |
| 632 | +/* | |
| 633 | +** Render the date string given as a hyperlink to a "circa" timeline. | |
| 634 | +*/ | |
| 635 | +void link_to_date(const char *zDate, const char *zSuffix){ | |
| 636 | + @ <a href="%s(g.zBaseURL)/timeline?c=%t(zDate)">%h(zDate)</a>%s(zSuffix) | |
| 637 | +} | |
| 606 | 638 | |
| 607 | 639 | /* |
| 608 | 640 | ** The input query q selects various records. Print a human-readable |
| 609 | 641 | ** summary of those records. |
| 610 | 642 | ** |
| 611 | 643 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -54,11 +54,11 @@ | |
| 54 | ){ |
| 55 | char zShortUuid[UUID_SIZE+1]; |
| 56 | sprintf(zShortUuid, "%.10s", zUuid); |
| 57 | if( g.okHistory ){ |
| 58 | @ <a onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")' |
| 59 | @ href="%s(g.zBaseURL)/ci/%s(zUuid)">[%s(zShortUuid)]</a> |
| 60 | }else{ |
| 61 | @ <b onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")'> |
| 62 | @ [%s(zShortUuid)]</b> |
| 63 | } |
| 64 | } |
| @@ -308,10 +308,11 @@ | |
| 308 | ** |
| 309 | ** Query parameters: |
| 310 | ** |
| 311 | ** a=TIMESTAMP after this date |
| 312 | ** b=TIMESTAMP before this date. |
| 313 | ** n=COUNT number of events in output |
| 314 | ** p=RID artifact RID and up to COUNT parents and ancestors |
| 315 | ** d=RID artifact RID and up to COUNT descendants |
| 316 | ** t=TAGID show only check-ins with the given tagid |
| 317 | ** u=USER only if belonging to this user |
| @@ -334,10 +335,11 @@ | |
| 334 | int d_rid = atoi(PD("d","0")); /* artifact d and its descendants */ |
| 335 | const char *zUser = P("u"); /* All entries by this user if not NULL */ |
| 336 | const char *zType = PD("y","all"); /* Type of events. All if NULL */ |
| 337 | const char *zAfter = P("a"); /* Events after this time */ |
| 338 | const char *zBefore = P("b"); /* Events before this time */ |
| 339 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 340 | HQuery url; /* URL for various branch links */ |
| 341 | int tagid; /* Tag ID */ |
| 342 | |
| 343 | /* To view the timeline, must have permission to read project data. |
| @@ -442,10 +444,31 @@ | |
| 442 | " ORDER BY event.mtime DESC", zBefore); |
| 443 | url_add_parameter(&url, "b", zBefore); |
| 444 | }else{ |
| 445 | zBefore = 0; |
| 446 | } |
| 447 | }else{ |
| 448 | blob_appendf(&sql, " ORDER BY event.mtime DESC"); |
| 449 | } |
| 450 | blob_appendf(&sql, " LIMIT %d", nEntry); |
| 451 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -452,11 +475,11 @@ | |
| 452 | |
| 453 | n = db_int(0, "SELECT count(*) FROM timeline"); |
| 454 | if( n<nEntry && zAfter ){ |
| 455 | cgi_redirect(url_render(&url, "a", 0, "b", 0)); |
| 456 | } |
| 457 | if( zAfter==0 && zBefore==0 ){ |
| 458 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 459 | }else{ |
| 460 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 461 | } |
| 462 | if( zUser ){ |
| @@ -467,10 +490,12 @@ | |
| 467 | } |
| 468 | if( zAfter ){ |
| 469 | blob_appendf(&desc, " occurring on or after %h.<br>", zAfter); |
| 470 | }else if( zBefore ){ |
| 471 | blob_appendf(&desc, " occurring on or before %h.<br>", zBefore); |
| 472 | } |
| 473 | if( g.okHistory ){ |
| 474 | if( zAfter || n==nEntry ){ |
| 475 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline"); |
| 476 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| @@ -601,10 +626,17 @@ | |
| 601 | @ } |
| 602 | @ } |
| 603 | @ </script> |
| 604 | style_footer(); |
| 605 | } |
| 606 | |
| 607 | /* |
| 608 | ** The input query q selects various records. Print a human-readable |
| 609 | ** summary of those records. |
| 610 | ** |
| 611 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -54,11 +54,11 @@ | |
| 54 | ){ |
| 55 | char zShortUuid[UUID_SIZE+1]; |
| 56 | sprintf(zShortUuid, "%.10s", zUuid); |
| 57 | if( g.okHistory ){ |
| 58 | @ <a onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")' |
| 59 | @ href="%s(g.zBaseURL)/vdiff/%s(zUuid)">[%s(zShortUuid)]</a> |
| 60 | }else{ |
| 61 | @ <b onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")'> |
| 62 | @ [%s(zShortUuid)]</b> |
| 63 | } |
| 64 | } |
| @@ -308,10 +308,11 @@ | |
| 308 | ** |
| 309 | ** Query parameters: |
| 310 | ** |
| 311 | ** a=TIMESTAMP after this date |
| 312 | ** b=TIMESTAMP before this date. |
| 313 | ** c=TIMESTAMP "circa" this date. |
| 314 | ** n=COUNT number of events in output |
| 315 | ** p=RID artifact RID and up to COUNT parents and ancestors |
| 316 | ** d=RID artifact RID and up to COUNT descendants |
| 317 | ** t=TAGID show only check-ins with the given tagid |
| 318 | ** u=USER only if belonging to this user |
| @@ -334,10 +335,11 @@ | |
| 335 | int d_rid = atoi(PD("d","0")); /* artifact d and its descendants */ |
| 336 | const char *zUser = P("u"); /* All entries by this user if not NULL */ |
| 337 | const char *zType = PD("y","all"); /* Type of events. All if NULL */ |
| 338 | const char *zAfter = P("a"); /* Events after this time */ |
| 339 | const char *zBefore = P("b"); /* Events before this time */ |
| 340 | const char *zCirca = P("c"); /* Events near this time */ |
| 341 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 342 | HQuery url; /* URL for various branch links */ |
| 343 | int tagid; /* Tag ID */ |
| 344 | |
| 345 | /* To view the timeline, must have permission to read project data. |
| @@ -442,10 +444,31 @@ | |
| 444 | " ORDER BY event.mtime DESC", zBefore); |
| 445 | url_add_parameter(&url, "b", zBefore); |
| 446 | }else{ |
| 447 | zBefore = 0; |
| 448 | } |
| 449 | }else if( zCirca ){ |
| 450 | while( isspace(zCirca[0]) ){ zCirca++; } |
| 451 | if( zCirca[0] ){ |
| 452 | double rCirca = db_double(0.0, "SELECT julianday(%Q, 'utc')", zCirca); |
| 453 | Blob sql2; |
| 454 | blob_init(&sql2, blob_str(&sql), -1); |
| 455 | blob_appendf(&sql2, |
| 456 | " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", |
| 457 | rCirca, (nEntry+1)/2 |
| 458 | ); |
| 459 | db_multi_exec("%s", blob_str(&sql2)); |
| 460 | blob_reset(&sql2); |
| 461 | blob_appendf(&sql, |
| 462 | " AND event.mtime>=%f ORDER BY event.mtime ASC", |
| 463 | rCirca |
| 464 | ); |
| 465 | nEntry -= (nEntry+1)/2; |
| 466 | url_add_parameter(&url, "c", zCirca); |
| 467 | }else{ |
| 468 | zCirca = 0; |
| 469 | } |
| 470 | }else{ |
| 471 | blob_appendf(&sql, " ORDER BY event.mtime DESC"); |
| 472 | } |
| 473 | blob_appendf(&sql, " LIMIT %d", nEntry); |
| 474 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -452,11 +475,11 @@ | |
| 475 | |
| 476 | n = db_int(0, "SELECT count(*) FROM timeline"); |
| 477 | if( n<nEntry && zAfter ){ |
| 478 | cgi_redirect(url_render(&url, "a", 0, "b", 0)); |
| 479 | } |
| 480 | if( zAfter==0 && zBefore==0 && zCirca==0 ){ |
| 481 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 482 | }else{ |
| 483 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 484 | } |
| 485 | if( zUser ){ |
| @@ -467,10 +490,12 @@ | |
| 490 | } |
| 491 | if( zAfter ){ |
| 492 | blob_appendf(&desc, " occurring on or after %h.<br>", zAfter); |
| 493 | }else if( zBefore ){ |
| 494 | blob_appendf(&desc, " occurring on or before %h.<br>", zBefore); |
| 495 | }else if( zCirca ){ |
| 496 | blob_appendf(&desc, " occurring around %h.<br>", zCirca); |
| 497 | } |
| 498 | if( g.okHistory ){ |
| 499 | if( zAfter || n==nEntry ){ |
| 500 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline"); |
| 501 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| @@ -601,10 +626,17 @@ | |
| 626 | @ } |
| 627 | @ } |
| 628 | @ </script> |
| 629 | style_footer(); |
| 630 | } |
| 631 | |
| 632 | /* |
| 633 | ** Render the date string given as a hyperlink to a "circa" timeline. |
| 634 | */ |
| 635 | void link_to_date(const char *zDate, const char *zSuffix){ |
| 636 | @ <a href="%s(g.zBaseURL)/timeline?c=%t(zDate)">%h(zDate)</a>%s(zSuffix) |
| 637 | } |
| 638 | |
| 639 | /* |
| 640 | ** The input query q selects various records. Print a human-readable |
| 641 | ** summary of those records. |
| 642 | ** |
| 643 |