Fossil SCM
An attempt to improve the "age" display in the file tree viewer.
Commit
3bd9e9bf7e70c7240045df4cbc89311c9ec81939
Parent
f8d54372e76ca5d…
2 files changed
+40
-16
+5
-1
+40
-16
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -412,11 +412,12 @@ | ||
| 412 | 412 | const char *zCI = P("ci"); |
| 413 | 413 | int rid = 0; |
| 414 | 414 | char *zUuid = 0; |
| 415 | 415 | Blob dirname; |
| 416 | 416 | Manifest *pM = 0; |
| 417 | - double rNow = db_double(0.0,"SELECT julianday('now')"); | |
| 417 | + double rNow = 0; | |
| 418 | + char *zNow = 0; | |
| 418 | 419 | int nFile = 0; /* Number of files (or folders with "nofiles") */ |
| 419 | 420 | int linkTrunk = 1; /* include link to "trunk" */ |
| 420 | 421 | int linkTip = 1; /* include link to "tip" */ |
| 421 | 422 | const char *zRE; /* the value for the re=REGEXP query parameter */ |
| 422 | 423 | const char *zObjType; /* "files" by default or "folders" for "nofiles" */ |
| @@ -474,10 +475,13 @@ | ||
| 474 | 475 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 475 | 476 | linkTrunk = trunkRid && rid != trunkRid; |
| 476 | 477 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 477 | 478 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 478 | 479 | url_add_parameter(&sURI, "ci", zCI); |
| 480 | + rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 481 | + zNow = db_text("", "SELECT datetime(mtime,'localtime')" | |
| 482 | + " FROM event WHERE objid=%d", rid); | |
| 479 | 483 | }else{ |
| 480 | 484 | zCI = 0; |
| 481 | 485 | } |
| 482 | 486 | } |
| 483 | 487 | |
| @@ -593,22 +597,28 @@ | ||
| 593 | 597 | if( nD ){ |
| 594 | 598 | @ <li class="dir last"> |
| 595 | 599 | }else{ |
| 596 | 600 | @ <li class="dir subdir last"> |
| 597 | 601 | } |
| 602 | + @ <div class="filetreeline"> | |
| 598 | 603 | @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> |
| 604 | + if( zNow ){ | |
| 605 | + @ <div class="filetreeage">%s(zNow)</div> | |
| 606 | + } | |
| 607 | + @ </div> | |
| 599 | 608 | @ <ul> |
| 600 | 609 | for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ |
| 601 | 610 | const char *zLastClass = p->isLast ? " last" : ""; |
| 602 | 611 | if( p->isDir ){ |
| 603 | 612 | const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : ""; |
| 604 | - @ <li class="dir%s(zSubdirClass)%s(zLastClass)"> | |
| 613 | + @ <li class="dir%s(zSubdirClass)%s(zLastClass)"><div class="filetreeline"> | |
| 605 | 614 | @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> |
| 606 | - if( p->mtime>0 ){ | |
| 615 | + if( p->mtime>0.0 ){ | |
| 607 | 616 | char *zAge = human_readable_age(rNow - p->mtime); |
| 608 | - @ <div class="filetreeage">%s(zAge) ago</div> | |
| 617 | + @ <div class="filetreeage">%s(zAge)</div> | |
| 609 | 618 | } |
| 619 | + @ </div> | |
| 610 | 620 | if( startExpanded || p->nFullName<=nD ){ |
| 611 | 621 | @ <ul id="dir%d(nDir)"> |
| 612 | 622 | }else{ |
| 613 | 623 | @ <ul id="dir%d(nDir)" class="collapsed"> |
| 614 | 624 | } |
| @@ -619,15 +629,17 @@ | ||
| 619 | 629 | if( zCI ){ |
| 620 | 630 | zLink = href("%R/artifact/%s",p->zUuid); |
| 621 | 631 | }else{ |
| 622 | 632 | zLink = href("%R/finfo?name=%T",p->zFullName); |
| 623 | 633 | } |
| 624 | - @ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a> | |
| 634 | + @ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline"> | |
| 635 | + @ %z(zLink)%h(p->zName)</a> | |
| 625 | 636 | if( p->mtime>0 ){ |
| 626 | 637 | char *zAge = human_readable_age(rNow - p->mtime); |
| 627 | - @ <div class="filetreeage">%s(zAge) ago</div> | |
| 638 | + @ <div class="filetreeage">%s(zAge)</div> | |
| 628 | 639 | } |
| 640 | + @ </div> | |
| 629 | 641 | } |
| 630 | 642 | if( p->isLast ){ |
| 631 | 643 | int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); |
| 632 | 644 | while( nClose-- > 0 ){ |
| 633 | 645 | @ </ul> |
| @@ -692,16 +704,16 @@ | ||
| 692 | 704 | @ checkState(); |
| 693 | 705 | @ outer_ul.onclick = function(e){ |
| 694 | 706 | @ e = e || window.event; |
| 695 | 707 | @ var a = e.target || e.srcElement; |
| 696 | 708 | @ if( a.nodeName!='A' ) return true; |
| 697 | - @ if( a.parentNode==subdir ){ | |
| 709 | + @ if( a.parentNode.parentNode==subdir ){ | |
| 698 | 710 | @ toggleAll(outer_ul); |
| 699 | 711 | @ return false; |
| 700 | 712 | @ } |
| 701 | 713 | @ if( !belowSubdir(a) ) return true; |
| 702 | - @ var ul = a.nextSibling; | |
| 714 | + @ var ul = a.parentNode.nextSibling; | |
| 703 | 715 | @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; |
| 704 | 716 | @ if( !ul ) return true; /* This is a file link, not a directory */ |
| 705 | 717 | @ toggleDir(ul); |
| 706 | 718 | @ return false; |
| 707 | 719 | @ } |
| @@ -790,19 +802,23 @@ | ||
| 790 | 802 | ** The string returned is obtained from fossil_malloc() and should be |
| 791 | 803 | ** freed by the caller. |
| 792 | 804 | */ |
| 793 | 805 | char *human_readable_age(double rAge){ |
| 794 | 806 | if( rAge*86400.0<120 ){ |
| 795 | - return mprintf("%d seconds", (int)(rAge*86400.0)); | |
| 807 | + if( rAge*86400.0<1.0 ){ | |
| 808 | + return mprintf("current"); | |
| 809 | + }else{ | |
| 810 | + return mprintf("-%d seconds", (int)(rAge*86400.0)); | |
| 811 | + } | |
| 796 | 812 | }else if( rAge*1440.0<90 ){ |
| 797 | - return mprintf("%.1f minutes", rAge*1440.0); | |
| 813 | + return mprintf("-%.1f minutes", rAge*1440.0); | |
| 798 | 814 | }else if( rAge*24.0<36 ){ |
| 799 | - return mprintf("%.1f hours", rAge*24.0); | |
| 815 | + return mprintf("-%.1f hours", rAge*24.0); | |
| 800 | 816 | }else if( rAge<365.0 ){ |
| 801 | - return mprintf("%.1f days", rAge); | |
| 817 | + return mprintf("-%.1f days", rAge); | |
| 802 | 818 | }else{ |
| 803 | - return mprintf("%.2f years", rAge/365.0); | |
| 819 | + return mprintf("-%.2f years", rAge/365.0); | |
| 804 | 820 | } |
| 805 | 821 | } |
| 806 | 822 | |
| 807 | 823 | /* |
| 808 | 824 | ** COMMAND: test-fileage |
| @@ -844,10 +860,12 @@ | ||
| 844 | 860 | */ |
| 845 | 861 | void fileage_page(void){ |
| 846 | 862 | int rid; |
| 847 | 863 | const char *zName; |
| 848 | 864 | const char *zGlob; |
| 865 | + const char *zUuid; | |
| 866 | + const char *zNow; /* Time of checkin */ | |
| 849 | 867 | Stmt q1, q2; |
| 850 | 868 | double baseTime; |
| 851 | 869 | login_check_credentials(); |
| 852 | 870 | if( !g.perm.Read ){ login_needed(); return; } |
| 853 | 871 | zName = P("name"); |
| @@ -854,26 +872,32 @@ | ||
| 854 | 872 | if( zName==0 ) zName = "tip"; |
| 855 | 873 | rid = symbolic_name_to_rid(zName, "ci"); |
| 856 | 874 | if( rid==0 ){ |
| 857 | 875 | fossil_fatal("not a valid check-in: %s", zName); |
| 858 | 876 | } |
| 877 | + zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 878 | + baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid); | |
| 879 | + zNow = db_text("", "SELECT datetime(mtime,'localtime') FROM event" | |
| 880 | + " WHERE objid=%d", rid); | |
| 859 | 881 | style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); |
| 860 | 882 | style_header("File Ages"); |
| 861 | 883 | zGlob = P("glob"); |
| 862 | 884 | compute_fileage(rid,zGlob); |
| 863 | 885 | db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);"); |
| 864 | 886 | |
| 865 | - baseTime = db_double(0.0, "SELECT julianday('now');"); | |
| 866 | 887 | @ <h2>Most recent change to files in checkin |
| 867 | - @ %z(href("%R/info?name=%T",zName))%h(zName)</a> | |
| 888 | + @ %z(href("%R/info?name=%T",zUuid))%S(zUuid)</a> | |
| 868 | 889 | if( zGlob && zGlob[0] ){ |
| 869 | 890 | @ that match "%h(zGlob)" |
| 870 | 891 | } |
| 871 | 892 | @</h2> |
| 872 | 893 | @ |
| 894 | + @ <p>All times are shown relative to the check-in time for | |
| 895 | + @ %S(zUuid) which was %s(zNow).</p> | |
| 896 | + @ | |
| 873 | 897 | @ <div class='fileage'><table> |
| 874 | - @ <tr><th>Age</th><th>Files</th><th>Checkin</th></tr> | |
| 898 | + @ <tr><th>Time</th><th>Files</th><th>Checkin</th></tr> | |
| 875 | 899 | db_prepare(&q1, |
| 876 | 900 | "SELECT event.mtime, event.objid, blob.uuid,\n" |
| 877 | 901 | " coalesce(event.ecomment,event.comment),\n" |
| 878 | 902 | " coalesce(event.euser,event.user),\n" |
| 879 | 903 | " coalesce((SELECT value FROM tagxref\n" |
| 880 | 904 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -412,11 +412,12 @@ | |
| 412 | const char *zCI = P("ci"); |
| 413 | int rid = 0; |
| 414 | char *zUuid = 0; |
| 415 | Blob dirname; |
| 416 | Manifest *pM = 0; |
| 417 | double rNow = db_double(0.0,"SELECT julianday('now')"); |
| 418 | int nFile = 0; /* Number of files (or folders with "nofiles") */ |
| 419 | int linkTrunk = 1; /* include link to "trunk" */ |
| 420 | int linkTip = 1; /* include link to "tip" */ |
| 421 | const char *zRE; /* the value for the re=REGEXP query parameter */ |
| 422 | const char *zObjType; /* "files" by default or "folders" for "nofiles" */ |
| @@ -474,10 +475,13 @@ | |
| 474 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 475 | linkTrunk = trunkRid && rid != trunkRid; |
| 476 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 477 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 478 | url_add_parameter(&sURI, "ci", zCI); |
| 479 | }else{ |
| 480 | zCI = 0; |
| 481 | } |
| 482 | } |
| 483 | |
| @@ -593,22 +597,28 @@ | |
| 593 | if( nD ){ |
| 594 | @ <li class="dir last"> |
| 595 | }else{ |
| 596 | @ <li class="dir subdir last"> |
| 597 | } |
| 598 | @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> |
| 599 | @ <ul> |
| 600 | for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ |
| 601 | const char *zLastClass = p->isLast ? " last" : ""; |
| 602 | if( p->isDir ){ |
| 603 | const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : ""; |
| 604 | @ <li class="dir%s(zSubdirClass)%s(zLastClass)"> |
| 605 | @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> |
| 606 | if( p->mtime>0 ){ |
| 607 | char *zAge = human_readable_age(rNow - p->mtime); |
| 608 | @ <div class="filetreeage">%s(zAge) ago</div> |
| 609 | } |
| 610 | if( startExpanded || p->nFullName<=nD ){ |
| 611 | @ <ul id="dir%d(nDir)"> |
| 612 | }else{ |
| 613 | @ <ul id="dir%d(nDir)" class="collapsed"> |
| 614 | } |
| @@ -619,15 +629,17 @@ | |
| 619 | if( zCI ){ |
| 620 | zLink = href("%R/artifact/%s",p->zUuid); |
| 621 | }else{ |
| 622 | zLink = href("%R/finfo?name=%T",p->zFullName); |
| 623 | } |
| 624 | @ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a> |
| 625 | if( p->mtime>0 ){ |
| 626 | char *zAge = human_readable_age(rNow - p->mtime); |
| 627 | @ <div class="filetreeage">%s(zAge) ago</div> |
| 628 | } |
| 629 | } |
| 630 | if( p->isLast ){ |
| 631 | int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); |
| 632 | while( nClose-- > 0 ){ |
| 633 | @ </ul> |
| @@ -692,16 +704,16 @@ | |
| 692 | @ checkState(); |
| 693 | @ outer_ul.onclick = function(e){ |
| 694 | @ e = e || window.event; |
| 695 | @ var a = e.target || e.srcElement; |
| 696 | @ if( a.nodeName!='A' ) return true; |
| 697 | @ if( a.parentNode==subdir ){ |
| 698 | @ toggleAll(outer_ul); |
| 699 | @ return false; |
| 700 | @ } |
| 701 | @ if( !belowSubdir(a) ) return true; |
| 702 | @ var ul = a.nextSibling; |
| 703 | @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; |
| 704 | @ if( !ul ) return true; /* This is a file link, not a directory */ |
| 705 | @ toggleDir(ul); |
| 706 | @ return false; |
| 707 | @ } |
| @@ -790,19 +802,23 @@ | |
| 790 | ** The string returned is obtained from fossil_malloc() and should be |
| 791 | ** freed by the caller. |
| 792 | */ |
| 793 | char *human_readable_age(double rAge){ |
| 794 | if( rAge*86400.0<120 ){ |
| 795 | return mprintf("%d seconds", (int)(rAge*86400.0)); |
| 796 | }else if( rAge*1440.0<90 ){ |
| 797 | return mprintf("%.1f minutes", rAge*1440.0); |
| 798 | }else if( rAge*24.0<36 ){ |
| 799 | return mprintf("%.1f hours", rAge*24.0); |
| 800 | }else if( rAge<365.0 ){ |
| 801 | return mprintf("%.1f days", rAge); |
| 802 | }else{ |
| 803 | return mprintf("%.2f years", rAge/365.0); |
| 804 | } |
| 805 | } |
| 806 | |
| 807 | /* |
| 808 | ** COMMAND: test-fileage |
| @@ -844,10 +860,12 @@ | |
| 844 | */ |
| 845 | void fileage_page(void){ |
| 846 | int rid; |
| 847 | const char *zName; |
| 848 | const char *zGlob; |
| 849 | Stmt q1, q2; |
| 850 | double baseTime; |
| 851 | login_check_credentials(); |
| 852 | if( !g.perm.Read ){ login_needed(); return; } |
| 853 | zName = P("name"); |
| @@ -854,26 +872,32 @@ | |
| 854 | if( zName==0 ) zName = "tip"; |
| 855 | rid = symbolic_name_to_rid(zName, "ci"); |
| 856 | if( rid==0 ){ |
| 857 | fossil_fatal("not a valid check-in: %s", zName); |
| 858 | } |
| 859 | style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); |
| 860 | style_header("File Ages"); |
| 861 | zGlob = P("glob"); |
| 862 | compute_fileage(rid,zGlob); |
| 863 | db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);"); |
| 864 | |
| 865 | baseTime = db_double(0.0, "SELECT julianday('now');"); |
| 866 | @ <h2>Most recent change to files in checkin |
| 867 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a> |
| 868 | if( zGlob && zGlob[0] ){ |
| 869 | @ that match "%h(zGlob)" |
| 870 | } |
| 871 | @</h2> |
| 872 | @ |
| 873 | @ <div class='fileage'><table> |
| 874 | @ <tr><th>Age</th><th>Files</th><th>Checkin</th></tr> |
| 875 | db_prepare(&q1, |
| 876 | "SELECT event.mtime, event.objid, blob.uuid,\n" |
| 877 | " coalesce(event.ecomment,event.comment),\n" |
| 878 | " coalesce(event.euser,event.user),\n" |
| 879 | " coalesce((SELECT value FROM tagxref\n" |
| 880 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -412,11 +412,12 @@ | |
| 412 | const char *zCI = P("ci"); |
| 413 | int rid = 0; |
| 414 | char *zUuid = 0; |
| 415 | Blob dirname; |
| 416 | Manifest *pM = 0; |
| 417 | double rNow = 0; |
| 418 | char *zNow = 0; |
| 419 | int nFile = 0; /* Number of files (or folders with "nofiles") */ |
| 420 | int linkTrunk = 1; /* include link to "trunk" */ |
| 421 | int linkTip = 1; /* include link to "tip" */ |
| 422 | const char *zRE; /* the value for the re=REGEXP query parameter */ |
| 423 | const char *zObjType; /* "files" by default or "folders" for "nofiles" */ |
| @@ -474,10 +475,13 @@ | |
| 475 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 476 | linkTrunk = trunkRid && rid != trunkRid; |
| 477 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 478 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 479 | url_add_parameter(&sURI, "ci", zCI); |
| 480 | rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 481 | zNow = db_text("", "SELECT datetime(mtime,'localtime')" |
| 482 | " FROM event WHERE objid=%d", rid); |
| 483 | }else{ |
| 484 | zCI = 0; |
| 485 | } |
| 486 | } |
| 487 | |
| @@ -593,22 +597,28 @@ | |
| 597 | if( nD ){ |
| 598 | @ <li class="dir last"> |
| 599 | }else{ |
| 600 | @ <li class="dir subdir last"> |
| 601 | } |
| 602 | @ <div class="filetreeline"> |
| 603 | @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> |
| 604 | if( zNow ){ |
| 605 | @ <div class="filetreeage">%s(zNow)</div> |
| 606 | } |
| 607 | @ </div> |
| 608 | @ <ul> |
| 609 | for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ |
| 610 | const char *zLastClass = p->isLast ? " last" : ""; |
| 611 | if( p->isDir ){ |
| 612 | const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : ""; |
| 613 | @ <li class="dir%s(zSubdirClass)%s(zLastClass)"><div class="filetreeline"> |
| 614 | @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> |
| 615 | if( p->mtime>0.0 ){ |
| 616 | char *zAge = human_readable_age(rNow - p->mtime); |
| 617 | @ <div class="filetreeage">%s(zAge)</div> |
| 618 | } |
| 619 | @ </div> |
| 620 | if( startExpanded || p->nFullName<=nD ){ |
| 621 | @ <ul id="dir%d(nDir)"> |
| 622 | }else{ |
| 623 | @ <ul id="dir%d(nDir)" class="collapsed"> |
| 624 | } |
| @@ -619,15 +629,17 @@ | |
| 629 | if( zCI ){ |
| 630 | zLink = href("%R/artifact/%s",p->zUuid); |
| 631 | }else{ |
| 632 | zLink = href("%R/finfo?name=%T",p->zFullName); |
| 633 | } |
| 634 | @ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline"> |
| 635 | @ %z(zLink)%h(p->zName)</a> |
| 636 | if( p->mtime>0 ){ |
| 637 | char *zAge = human_readable_age(rNow - p->mtime); |
| 638 | @ <div class="filetreeage">%s(zAge)</div> |
| 639 | } |
| 640 | @ </div> |
| 641 | } |
| 642 | if( p->isLast ){ |
| 643 | int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); |
| 644 | while( nClose-- > 0 ){ |
| 645 | @ </ul> |
| @@ -692,16 +704,16 @@ | |
| 704 | @ checkState(); |
| 705 | @ outer_ul.onclick = function(e){ |
| 706 | @ e = e || window.event; |
| 707 | @ var a = e.target || e.srcElement; |
| 708 | @ if( a.nodeName!='A' ) return true; |
| 709 | @ if( a.parentNode.parentNode==subdir ){ |
| 710 | @ toggleAll(outer_ul); |
| 711 | @ return false; |
| 712 | @ } |
| 713 | @ if( !belowSubdir(a) ) return true; |
| 714 | @ var ul = a.parentNode.nextSibling; |
| 715 | @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; |
| 716 | @ if( !ul ) return true; /* This is a file link, not a directory */ |
| 717 | @ toggleDir(ul); |
| 718 | @ return false; |
| 719 | @ } |
| @@ -790,19 +802,23 @@ | |
| 802 | ** The string returned is obtained from fossil_malloc() and should be |
| 803 | ** freed by the caller. |
| 804 | */ |
| 805 | char *human_readable_age(double rAge){ |
| 806 | if( rAge*86400.0<120 ){ |
| 807 | if( rAge*86400.0<1.0 ){ |
| 808 | return mprintf("current"); |
| 809 | }else{ |
| 810 | return mprintf("-%d seconds", (int)(rAge*86400.0)); |
| 811 | } |
| 812 | }else if( rAge*1440.0<90 ){ |
| 813 | return mprintf("-%.1f minutes", rAge*1440.0); |
| 814 | }else if( rAge*24.0<36 ){ |
| 815 | return mprintf("-%.1f hours", rAge*24.0); |
| 816 | }else if( rAge<365.0 ){ |
| 817 | return mprintf("-%.1f days", rAge); |
| 818 | }else{ |
| 819 | return mprintf("-%.2f years", rAge/365.0); |
| 820 | } |
| 821 | } |
| 822 | |
| 823 | /* |
| 824 | ** COMMAND: test-fileage |
| @@ -844,10 +860,12 @@ | |
| 860 | */ |
| 861 | void fileage_page(void){ |
| 862 | int rid; |
| 863 | const char *zName; |
| 864 | const char *zGlob; |
| 865 | const char *zUuid; |
| 866 | const char *zNow; /* Time of checkin */ |
| 867 | Stmt q1, q2; |
| 868 | double baseTime; |
| 869 | login_check_credentials(); |
| 870 | if( !g.perm.Read ){ login_needed(); return; } |
| 871 | zName = P("name"); |
| @@ -854,26 +872,32 @@ | |
| 872 | if( zName==0 ) zName = "tip"; |
| 873 | rid = symbolic_name_to_rid(zName, "ci"); |
| 874 | if( rid==0 ){ |
| 875 | fossil_fatal("not a valid check-in: %s", zName); |
| 876 | } |
| 877 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 878 | baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid); |
| 879 | zNow = db_text("", "SELECT datetime(mtime,'localtime') FROM event" |
| 880 | " WHERE objid=%d", rid); |
| 881 | style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); |
| 882 | style_header("File Ages"); |
| 883 | zGlob = P("glob"); |
| 884 | compute_fileage(rid,zGlob); |
| 885 | db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);"); |
| 886 | |
| 887 | @ <h2>Most recent change to files in checkin |
| 888 | @ %z(href("%R/info?name=%T",zUuid))%S(zUuid)</a> |
| 889 | if( zGlob && zGlob[0] ){ |
| 890 | @ that match "%h(zGlob)" |
| 891 | } |
| 892 | @</h2> |
| 893 | @ |
| 894 | @ <p>All times are shown relative to the check-in time for |
| 895 | @ %S(zUuid) which was %s(zNow).</p> |
| 896 | @ |
| 897 | @ <div class='fileage'><table> |
| 898 | @ <tr><th>Time</th><th>Files</th><th>Checkin</th></tr> |
| 899 | db_prepare(&q1, |
| 900 | "SELECT event.mtime, event.objid, blob.uuid,\n" |
| 901 | " coalesce(event.ecomment,event.comment),\n" |
| 902 | " coalesce(event.euser,event.user),\n" |
| 903 | " coalesce((SELECT value FROM tagxref\n" |
| 904 |
+5
-1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -839,19 +839,23 @@ | ||
| 839 | 839 | @ padding-left: 21px; |
| 840 | 840 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); |
| 841 | 841 | @ background-position: center left; |
| 842 | 842 | @ background-repeat: no-repeat; |
| 843 | 843 | }, |
| 844 | - { ".filetree .dir > a", | |
| 844 | + { ".filetree .dir > div.filetreeline > a", | |
| 845 | 845 | "tree-view directory links", |
| 846 | 846 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); |
| 847 | 847 | }, |
| 848 | 848 | { "div.filetreeage", |
| 849 | 849 | "Last change floating display on the right", |
| 850 | 850 | @ clear: right; |
| 851 | 851 | @ float: right; |
| 852 | 852 | }, |
| 853 | + { "div.filetreeline:hover", | |
| 854 | + "Highlight the line of a file tree", | |
| 855 | + @ background-color: #eee; | |
| 856 | + }, | |
| 853 | 857 | { "table.login_out", |
| 854 | 858 | "table format for login/out label/input table", |
| 855 | 859 | @ text-align: left; |
| 856 | 860 | @ margin-right: 10px; |
| 857 | 861 | @ margin-left: 10px; |
| 858 | 862 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -839,19 +839,23 @@ | |
| 839 | @ padding-left: 21px; |
| 840 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); |
| 841 | @ background-position: center left; |
| 842 | @ background-repeat: no-repeat; |
| 843 | }, |
| 844 | { ".filetree .dir > a", |
| 845 | "tree-view directory links", |
| 846 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); |
| 847 | }, |
| 848 | { "div.filetreeage", |
| 849 | "Last change floating display on the right", |
| 850 | @ clear: right; |
| 851 | @ float: right; |
| 852 | }, |
| 853 | { "table.login_out", |
| 854 | "table format for login/out label/input table", |
| 855 | @ text-align: left; |
| 856 | @ margin-right: 10px; |
| 857 | @ margin-left: 10px; |
| 858 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -839,19 +839,23 @@ | |
| 839 | @ padding-left: 21px; |
| 840 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); |
| 841 | @ background-position: center left; |
| 842 | @ background-repeat: no-repeat; |
| 843 | }, |
| 844 | { ".filetree .dir > div.filetreeline > a", |
| 845 | "tree-view directory links", |
| 846 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); |
| 847 | }, |
| 848 | { "div.filetreeage", |
| 849 | "Last change floating display on the right", |
| 850 | @ clear: right; |
| 851 | @ float: right; |
| 852 | }, |
| 853 | { "div.filetreeline:hover", |
| 854 | "Highlight the line of a file tree", |
| 855 | @ background-color: #eee; |
| 856 | }, |
| 857 | { "table.login_out", |
| 858 | "table format for login/out label/input table", |
| 859 | @ text-align: left; |
| 860 | @ margin-right: 10px; |
| 861 | @ margin-left: 10px; |
| 862 |