Fossil SCM
Enhance the "fileage" webpage so that it shows ages relative to current time rather than relative to the last checkin, so that it shows associated checkin comments, and so that it is styled using CSS.
Commit
31b5dffa768db70cefd4a5c736582d70dcc698ce
Parent
3a00b612d449eaf…
2 files changed
+60
-37
+19
+60
-37
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -838,15 +838,13 @@ | ||
| 838 | 838 | ** (e.g. *.c or *.txt). |
| 839 | 839 | */ |
| 840 | 840 | void fileage_page(void){ |
| 841 | 841 | int rid; |
| 842 | 842 | const char *zName; |
| 843 | - char *zBaseTime; | |
| 844 | 843 | const char *zGlob; |
| 845 | - Stmt q; | |
| 844 | + Stmt q1, q2; | |
| 846 | 845 | double baseTime; |
| 847 | - int lastMid = -1; | |
| 848 | 846 | login_check_credentials(); |
| 849 | 847 | if( !g.perm.Read ){ login_needed(); return; } |
| 850 | 848 | zName = P("name"); |
| 851 | 849 | if( zName==0 ) zName = "tip"; |
| 852 | 850 | rid = symbolic_name_to_rid(zName, "ci"); |
| @@ -855,44 +853,69 @@ | ||
| 855 | 853 | } |
| 856 | 854 | style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); |
| 857 | 855 | style_header("File Ages"); |
| 858 | 856 | zGlob = P("glob"); |
| 859 | 857 | compute_fileage(rid,zGlob); |
| 860 | - baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 861 | - zBaseTime = db_text("","SELECT datetime(%.20g%s)", baseTime, timeline_utc()); | |
| 862 | - @ <h2>File Ages For Check-in | |
| 863 | - @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> | |
| 864 | - @ | |
| 865 | - @ <p>The times given are relative to | |
| 866 | - @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the | |
| 867 | - @ check-in time for | |
| 868 | - @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p> | |
| 869 | - @ | |
| 870 | - @ <table border=0 cellspacing=0 cellpadding=0> | |
| 871 | - db_prepare(&q, | |
| 872 | - "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname" | |
| 873 | - " FROM fileage" | |
| 874 | - " ORDER BY mtime DESC, mid, pathname" | |
| 875 | - ); | |
| 876 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 877 | - double age = baseTime - db_column_double(&q, 0); | |
| 878 | - int mid = db_column_int(&q, 2); | |
| 879 | - const char *zFUuid = db_column_text(&q, 1); | |
| 880 | - char *zAge = 0; | |
| 881 | - if( lastMid!=mid ){ | |
| 882 | - @ <tr><td colspan=3><hr></tr> | |
| 883 | - lastMid = mid; | |
| 884 | - zAge = human_readable_age(age); | |
| 885 | - } | |
| 886 | - @ <tr> | |
| 887 | - @ <td>%s(zAge?zAge:"") | |
| 888 | - @ <td width="25"> | |
| 889 | - @ <td>%z(href("%R/artifact/%s?ln", zFUuid))%h(db_column_text(&q, 3))</a> | |
| 890 | - @ </tr> | |
| 858 | + db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);"); | |
| 859 | + | |
| 860 | + baseTime = db_double(0.0, "SELECT julianday('now');"); | |
| 861 | + @ <h2>Most recent change to files in checkin | |
| 862 | + @ %z(href("%R/info?name=%T",zName))%h(zName)</a> | |
| 863 | + if( zGlob && zGlob[0] ){ | |
| 864 | + @ that match "%h(zGlob)" | |
| 865 | + } | |
| 866 | + @</h2> | |
| 867 | + @ | |
| 868 | + @ <div class='fileage'><table> | |
| 869 | + @ <tr><th>Age</th><th>Files</th><th>Checkin</th></tr> | |
| 870 | + db_prepare(&q1, | |
| 871 | + "SELECT event.mtime, event.objid, blob.uuid,\n" | |
| 872 | + " coalesce(event.ecomment,event.comment),\n" | |
| 873 | + " coalesce(event.euser,event.user),\n" | |
| 874 | + " coalesce((SELECT value FROM tagxref\n" | |
| 875 | + " WHERE tagtype>0 AND tagid=%d\n" | |
| 876 | + " AND rid=event.objid),'trunk')\n" | |
| 877 | + " FROM event, blob\n" | |
| 878 | + " WHERE event.objid IN (SELECT mid FROM fileage)\n" | |
| 879 | + " AND blob.rid=event.objid\n" | |
| 880 | + " ORDER BY event.mtime DESC;", | |
| 881 | + TAG_BRANCH | |
| 882 | + ); | |
| 883 | + db_prepare(&q2, | |
| 884 | + "SELECT blob.uuid, filename.name\n" | |
| 885 | + " FROM fileage, blob, filename\n" | |
| 886 | + " WHERE fileage.mid=:mid AND filename.fnid=fileage.fnid" | |
| 887 | + " AND blob.rid=fileage.fid;" | |
| 888 | + ); | |
| 889 | + while( db_step(&q1)==SQLITE_ROW ){ | |
| 890 | + double age = baseTime - db_column_double(&q1, 0); | |
| 891 | + int mid = db_column_int(&q1, 1); | |
| 892 | + const char *zUuid = db_column_text(&q1, 2); | |
| 893 | + const char *zComment = db_column_text(&q1, 3); | |
| 894 | + const char *zUser = db_column_text(&q1, 4); | |
| 895 | + const char *zBranch = db_column_text(&q1, 5); | |
| 896 | + char *zAge = human_readable_age(age); | |
| 897 | + @ <tr><td>%s(zAge)</td> | |
| 898 | + @ <td> | |
| 899 | + db_bind_int(&q2, ":mid", mid); | |
| 900 | + while( db_step(&q2)==SQLITE_ROW ){ | |
| 901 | + const char *zFUuid = db_column_text(&q2,0); | |
| 902 | + const char *zFile = db_column_text(&q2,1); | |
| 903 | + @ %z(href("%R/artifact/%s",zFUuid))%h(zFile)</a><br> | |
| 904 | + } | |
| 905 | + db_reset(&q2); | |
| 906 | + @ </td> | |
| 907 | + @ <td> | |
| 908 | + @ %z(href("%R/info/%s",zUuid))[%S(zUuid)]</a> | |
| 909 | + @ %W(zComment) (user: | |
| 910 | + @ %z(href("%R/timeline?u=%t&c=%t&nd&n=200",zUser,zUuid))%h(zUser)</a>, | |
| 911 | + @ branch: | |
| 912 | + @ %z(href("%R/timeline?r=%t&c=%t&nd&n=200",zBranch,zUuid))%h(zBranch)</a>) | |
| 913 | + @ </td></tr> | |
| 891 | 914 | @ |
| 892 | 915 | fossil_free(zAge); |
| 893 | 916 | } |
| 894 | - @ <tr><td colspan=3><hr></tr> | |
| 895 | - @ </table> | |
| 896 | - db_finalize(&q); | |
| 917 | + @ </table></div> | |
| 918 | + db_finalize(&q1); | |
| 919 | + db_finalize(&q2); | |
| 897 | 920 | style_footer(); |
| 898 | 921 | } |
| 899 | 922 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -838,15 +838,13 @@ | |
| 838 | ** (e.g. *.c or *.txt). |
| 839 | */ |
| 840 | void fileage_page(void){ |
| 841 | int rid; |
| 842 | const char *zName; |
| 843 | char *zBaseTime; |
| 844 | const char *zGlob; |
| 845 | Stmt q; |
| 846 | double baseTime; |
| 847 | int lastMid = -1; |
| 848 | login_check_credentials(); |
| 849 | if( !g.perm.Read ){ login_needed(); return; } |
| 850 | zName = P("name"); |
| 851 | if( zName==0 ) zName = "tip"; |
| 852 | rid = symbolic_name_to_rid(zName, "ci"); |
| @@ -855,44 +853,69 @@ | |
| 855 | } |
| 856 | style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); |
| 857 | style_header("File Ages"); |
| 858 | zGlob = P("glob"); |
| 859 | compute_fileage(rid,zGlob); |
| 860 | baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 861 | zBaseTime = db_text("","SELECT datetime(%.20g%s)", baseTime, timeline_utc()); |
| 862 | @ <h2>File Ages For Check-in |
| 863 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> |
| 864 | @ |
| 865 | @ <p>The times given are relative to |
| 866 | @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the |
| 867 | @ check-in time for |
| 868 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p> |
| 869 | @ |
| 870 | @ <table border=0 cellspacing=0 cellpadding=0> |
| 871 | db_prepare(&q, |
| 872 | "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname" |
| 873 | " FROM fileage" |
| 874 | " ORDER BY mtime DESC, mid, pathname" |
| 875 | ); |
| 876 | while( db_step(&q)==SQLITE_ROW ){ |
| 877 | double age = baseTime - db_column_double(&q, 0); |
| 878 | int mid = db_column_int(&q, 2); |
| 879 | const char *zFUuid = db_column_text(&q, 1); |
| 880 | char *zAge = 0; |
| 881 | if( lastMid!=mid ){ |
| 882 | @ <tr><td colspan=3><hr></tr> |
| 883 | lastMid = mid; |
| 884 | zAge = human_readable_age(age); |
| 885 | } |
| 886 | @ <tr> |
| 887 | @ <td>%s(zAge?zAge:"") |
| 888 | @ <td width="25"> |
| 889 | @ <td>%z(href("%R/artifact/%s?ln", zFUuid))%h(db_column_text(&q, 3))</a> |
| 890 | @ </tr> |
| 891 | @ |
| 892 | fossil_free(zAge); |
| 893 | } |
| 894 | @ <tr><td colspan=3><hr></tr> |
| 895 | @ </table> |
| 896 | db_finalize(&q); |
| 897 | style_footer(); |
| 898 | } |
| 899 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -838,15 +838,13 @@ | |
| 838 | ** (e.g. *.c or *.txt). |
| 839 | */ |
| 840 | void fileage_page(void){ |
| 841 | int rid; |
| 842 | const char *zName; |
| 843 | const char *zGlob; |
| 844 | Stmt q1, q2; |
| 845 | double baseTime; |
| 846 | login_check_credentials(); |
| 847 | if( !g.perm.Read ){ login_needed(); return; } |
| 848 | zName = P("name"); |
| 849 | if( zName==0 ) zName = "tip"; |
| 850 | rid = symbolic_name_to_rid(zName, "ci"); |
| @@ -855,44 +853,69 @@ | |
| 853 | } |
| 854 | style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); |
| 855 | style_header("File Ages"); |
| 856 | zGlob = P("glob"); |
| 857 | compute_fileage(rid,zGlob); |
| 858 | db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);"); |
| 859 | |
| 860 | baseTime = db_double(0.0, "SELECT julianday('now');"); |
| 861 | @ <h2>Most recent change to files in checkin |
| 862 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a> |
| 863 | if( zGlob && zGlob[0] ){ |
| 864 | @ that match "%h(zGlob)" |
| 865 | } |
| 866 | @</h2> |
| 867 | @ |
| 868 | @ <div class='fileage'><table> |
| 869 | @ <tr><th>Age</th><th>Files</th><th>Checkin</th></tr> |
| 870 | db_prepare(&q1, |
| 871 | "SELECT event.mtime, event.objid, blob.uuid,\n" |
| 872 | " coalesce(event.ecomment,event.comment),\n" |
| 873 | " coalesce(event.euser,event.user),\n" |
| 874 | " coalesce((SELECT value FROM tagxref\n" |
| 875 | " WHERE tagtype>0 AND tagid=%d\n" |
| 876 | " AND rid=event.objid),'trunk')\n" |
| 877 | " FROM event, blob\n" |
| 878 | " WHERE event.objid IN (SELECT mid FROM fileage)\n" |
| 879 | " AND blob.rid=event.objid\n" |
| 880 | " ORDER BY event.mtime DESC;", |
| 881 | TAG_BRANCH |
| 882 | ); |
| 883 | db_prepare(&q2, |
| 884 | "SELECT blob.uuid, filename.name\n" |
| 885 | " FROM fileage, blob, filename\n" |
| 886 | " WHERE fileage.mid=:mid AND filename.fnid=fileage.fnid" |
| 887 | " AND blob.rid=fileage.fid;" |
| 888 | ); |
| 889 | while( db_step(&q1)==SQLITE_ROW ){ |
| 890 | double age = baseTime - db_column_double(&q1, 0); |
| 891 | int mid = db_column_int(&q1, 1); |
| 892 | const char *zUuid = db_column_text(&q1, 2); |
| 893 | const char *zComment = db_column_text(&q1, 3); |
| 894 | const char *zUser = db_column_text(&q1, 4); |
| 895 | const char *zBranch = db_column_text(&q1, 5); |
| 896 | char *zAge = human_readable_age(age); |
| 897 | @ <tr><td>%s(zAge)</td> |
| 898 | @ <td> |
| 899 | db_bind_int(&q2, ":mid", mid); |
| 900 | while( db_step(&q2)==SQLITE_ROW ){ |
| 901 | const char *zFUuid = db_column_text(&q2,0); |
| 902 | const char *zFile = db_column_text(&q2,1); |
| 903 | @ %z(href("%R/artifact/%s",zFUuid))%h(zFile)</a><br> |
| 904 | } |
| 905 | db_reset(&q2); |
| 906 | @ </td> |
| 907 | @ <td> |
| 908 | @ %z(href("%R/info/%s",zUuid))[%S(zUuid)]</a> |
| 909 | @ %W(zComment) (user: |
| 910 | @ %z(href("%R/timeline?u=%t&c=%t&nd&n=200",zUser,zUuid))%h(zUser)</a>, |
| 911 | @ branch: |
| 912 | @ %z(href("%R/timeline?r=%t&c=%t&nd&n=200",zBranch,zUuid))%h(zBranch)</a>) |
| 913 | @ </td></tr> |
| 914 | @ |
| 915 | fossil_free(zAge); |
| 916 | } |
| 917 | @ </table></div> |
| 918 | db_finalize(&q1); |
| 919 | db_finalize(&q2); |
| 920 | style_footer(); |
| 921 | } |
| 922 |
+19
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -1219,10 +1219,29 @@ | ||
| 1219 | 1219 | "Class for the /admin_log table", |
| 1220 | 1220 | @ text-align: left; |
| 1221 | 1221 | @ vertical-align: top; |
| 1222 | 1222 | @ white-space: nowrap; |
| 1223 | 1223 | }, |
| 1224 | + { ".fileage table", | |
| 1225 | + "The fileage table", | |
| 1226 | + @ border-spacing: 0; | |
| 1227 | + }, | |
| 1228 | + { ".fileage td", | |
| 1229 | + "fileage table cells", | |
| 1230 | + @ vertical-align: top; | |
| 1231 | + @ text-align: left; | |
| 1232 | + @ border-top: 1px solid black; | |
| 1233 | + }, | |
| 1234 | + { ".fileage td:first-child", | |
| 1235 | + "fileage first column (the age)", | |
| 1236 | + @ white-space: nowrap; | |
| 1237 | + }, | |
| 1238 | + { ".fileage td:first-child + td", | |
| 1239 | + "fileage second column (the filename)", | |
| 1240 | + @ padding-left: 1em; | |
| 1241 | + @ padding-right: 1em; | |
| 1242 | + }, | |
| 1224 | 1243 | { 0, |
| 1225 | 1244 | 0, |
| 1226 | 1245 | 0 |
| 1227 | 1246 | } |
| 1228 | 1247 | }; |
| 1229 | 1248 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1219,10 +1219,29 @@ | |
| 1219 | "Class for the /admin_log table", |
| 1220 | @ text-align: left; |
| 1221 | @ vertical-align: top; |
| 1222 | @ white-space: nowrap; |
| 1223 | }, |
| 1224 | { 0, |
| 1225 | 0, |
| 1226 | 0 |
| 1227 | } |
| 1228 | }; |
| 1229 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1219,10 +1219,29 @@ | |
| 1219 | "Class for the /admin_log table", |
| 1220 | @ text-align: left; |
| 1221 | @ vertical-align: top; |
| 1222 | @ white-space: nowrap; |
| 1223 | }, |
| 1224 | { ".fileage table", |
| 1225 | "The fileage table", |
| 1226 | @ border-spacing: 0; |
| 1227 | }, |
| 1228 | { ".fileage td", |
| 1229 | "fileage table cells", |
| 1230 | @ vertical-align: top; |
| 1231 | @ text-align: left; |
| 1232 | @ border-top: 1px solid black; |
| 1233 | }, |
| 1234 | { ".fileage td:first-child", |
| 1235 | "fileage first column (the age)", |
| 1236 | @ white-space: nowrap; |
| 1237 | }, |
| 1238 | { ".fileage td:first-child + td", |
| 1239 | "fileage second column (the filename)", |
| 1240 | @ padding-left: 1em; |
| 1241 | @ padding-right: 1em; |
| 1242 | }, |
| 1243 | { 0, |
| 1244 | 0, |
| 1245 | 0 |
| 1246 | } |
| 1247 | }; |
| 1248 |