Fossil SCM

Replaced /activity with /stats_report. Supported by-month and by-year reports. Use user=NAME to limit report to that user (no UI yet for user selection).

stephan 2013-05-05 12:56 trunk
Commit 0de658266004a9436119e852a6b144e3ab0db2ba
3 files changed +7 -4 +122 -23 +9
+7 -4
--- src/style.c
+++ src/style.c
@@ -613,19 +613,22 @@
613613
@ vertical-align: top;
614614
@ text-align: right;
615615
@ padding: 0.2ex 2ex;
616616
@ }
617617
@
618
-@ /* .activity-* are for the /activity views */
619
-@ .activity-graph-line {
618
+@ /* .statistics-report-* are for the /stats_report views */
619
+@ .statistics-report-graph-line {
620620
@ background-color: #446979;
621621
@ }
622
-@ .activity-table-commits-by-month th {
622
+@ .statistics-report-table-events th {
623623
@ padding: 0 1em 0 1em;
624624
@ }
625
-@ .activity-table-commits-by-month td {
625
+@ .statistics-report-table-events td {
626626
@ padding: 0.1em 1em 0.1em 1em;
627
+@ }
628
+@ .statistics-report-row-year {
629
+@ text-align: left;
627630
@ }
628631
@ /* row0 and row1 are for alternating table row colors */
629632
@ tr.row0 {
630633
@ background: #fff;
631634
@ }
632635
--- src/style.c
+++ src/style.c
@@ -613,19 +613,22 @@
613 @ vertical-align: top;
614 @ text-align: right;
615 @ padding: 0.2ex 2ex;
616 @ }
617 @
618 @ /* .activity-* are for the /activity views */
619 @ .activity-graph-line {
620 @ background-color: #446979;
621 @ }
622 @ .activity-table-commits-by-month th {
623 @ padding: 0 1em 0 1em;
624 @ }
625 @ .activity-table-commits-by-month td {
626 @ padding: 0.1em 1em 0.1em 1em;
 
 
 
627 @ }
628 @ /* row0 and row1 are for alternating table row colors */
629 @ tr.row0 {
630 @ background: #fff;
631 @ }
632
--- src/style.c
+++ src/style.c
@@ -613,19 +613,22 @@
613 @ vertical-align: top;
614 @ text-align: right;
615 @ padding: 0.2ex 2ex;
616 @ }
617 @
618 @ /* .statistics-report-* are for the /stats_report views */
619 @ .statistics-report-graph-line {
620 @ background-color: #446979;
621 @ }
622 @ .statistics-report-table-events th {
623 @ padding: 0 1em 0 1em;
624 @ }
625 @ .statistics-report-table-events td {
626 @ padding: 0.1em 1em 0.1em 1em;
627 @ }
628 @ .statistics-report-row-year {
629 @ text-align: left;
630 @ }
631 @ /* row0 and row1 are for alternating table row colors */
632 @ tr.row0 {
633 @ background: #fff;
634 @ }
635
+122 -23
--- src/timeline.c
+++ src/timeline.c
@@ -1826,53 +1826,152 @@
18261826
@ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
18271827
}
18281828
db_finalize(&q);
18291829
style_footer();
18301830
}
1831
+
1832
+
18311833
18321834
/*
1833
-** WEBPAGE: activity
1834
-**
1835
-** Shows an activity report for the repository.
1835
+** Implements the "byyear" and "bymonth" reports for /stats_report.
1836
+** If includeMonth is true then it generates the "bymonth" report,
1837
+** else the "byyear" report. If zUserName is not NULL and not empty
1838
+** then the report is restricted to events created by the named user
1839
+** account.
18361840
*/
1837
-void activity_page(){
1841
+static void stats_report_bymonthyear(char includeMonth,
1842
+ char const * zUserName){
18381843
Stmt query = empty_Stmt;
1839
- int const nPixelsPerEvent = 1;
1840
- int nRowNumber = 0;
1841
- int nCommitCount = 0;
1842
- int rowClass = 0;
1843
- style_header("Repository Activity");
1844
- db_prepare(&query,
1845
- "SELECT substr(date(mtime),1,7) AS Month, "
1846
- "count(*) AS Commits FROM event "
1847
- "GROUP BY Month "
1848
- "ORDER BY Month DESC", -1);
1849
- @ <h1>Timeline Events by Month</h1>
1850
- @ <table class='activity-table-commits-by-month' border='0' cellpadding='2' cellspacing='0'>
1844
+ int const nPixelsPerEvent = 1; /* for sizing the "graph" part */
1845
+ int nRowNumber = 0; /* current TR number */
1846
+ int nEventTotal = 0; /* Total event count */
1847
+ int rowClass = 0; /* counter for alternating
1848
+ row colors */
1849
+ Blob sql = empty_blob; /* SQL */
1850
+ char const * zTimeLabel = includeMonth ? "Year/Month" : "Year";
1851
+ char zPrevYear[5] = {0}; /* For keeping track of when
1852
+ we change years while looping */
1853
+ int nEventsPerYear = 0; /* Total even count for the
1854
+ current year */
1855
+ char showYearTotal = 0; /* Flag telling us when to show
1856
+ the per-year event totals */
1857
+ Blob header = empty_blob; /* Page header text */
1858
+ blob_appendf(&header, "Timeline Events by %s", zTimeLabel);
1859
+ blob_appendf(&sql,
1860
+ "SELECT substr(date(mtime),1,%d) AS timeframe, "
1861
+ "count(*) AS eventCount "
1862
+ "FROM event ",
1863
+ includeMonth ? 7 : 4);
1864
+ if(zUserName&&*zUserName){
1865
+ blob_appendf(&sql, " WHERE user=%Q ", zUserName);
1866
+ blob_appendf(&header," for user %q", zUserName);
1867
+ }
1868
+ blob_append(&sql,
1869
+ " GROUP BY timeframe"
1870
+ " ORDER BY timeframe DESC",
1871
+ -1);
1872
+ db_prepare(&query, blob_str(&sql));
1873
+ blob_reset(&sql);
1874
+ @ <h1>%b(&header)</h1>
1875
+ @ <table class='statistics-report-table-events' border='0' cellpadding='2' cellspacing='0'>
18511876
@ <thead>
1852
- @ <th>Year/Month</th>
1877
+ @ <th>%s(zTimeLabel)</th>
18531878
@ <th>Events</th>
18541879
@ <th><!-- relative commits graph --></th>
18551880
@ </thead><tbody>
1881
+ blob_reset(&header);
18561882
while( SQLITE_ROW == db_step(&query) ){
1857
- char const * zMonth = db_column_text(&query, 0);
1883
+ char const * zTimeframe = db_column_text(&query, 0);
18581884
int const nCount = db_column_int(&query, 1);
1859
- int const nSize = nPixelsPerEvent * nCount;
1885
+ int const nSize = 1 + ((nPixelsPerEvent * nCount)
1886
+ / (includeMonth ? 1 : 10));
1887
+ showYearTotal = 0;
1888
+ if(includeMonth){
1889
+ /* For Month/year view, add a separator for each distinct year. */
1890
+ if(!*zPrevYear ||
1891
+ (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
1892
+ showYearTotal = *zPrevYear;
1893
+ if(showYearTotal){
1894
+ rowClass = ++nRowNumber % 2;
1895
+ @ <tr class='row%d(rowClass)'>
1896
+ @ <td></td>
1897
+ @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
1898
+ @</tr>
1899
+ }
1900
+ nEventsPerYear = 0;
1901
+ memcpy(zPrevYear,zTimeframe,4);
1902
+ rowClass = ++nRowNumber % 2;
1903
+ @ <tr class='row%d(rowClass)'>
1904
+ @ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
1905
+ @ </tr>
1906
+ }
1907
+ }
18601908
rowClass = ++nRowNumber % 2;
1861
- nCommitCount += nCount;
1909
+ nEventTotal += nCount;
1910
+ nEventsPerYear += nCount;
18621911
@<tr class='row%d(rowClass)'>
18631912
@ <td>
1864
- @ <a href="%s(g.zTop)/timeline?ym=%s(zMonth)&n=%d(nCount)" target="_new">%s(zMonth)</a>
1913
+ if(includeMonth){
1914
+ @ <a href="%s(g.zTop)/timeline?ym=%s(zTimeframe)&n=%d(nCount)" target="_new">%s(zTimeframe)</a>
1915
+ }else {
1916
+ @ %s(zTimeframe)
1917
+ }
18651918
@ </td><td>%d(nCount)</td>
18661919
@ <td>
1867
- @ <div class='activity-graph-line' style='height:16px; width:%d(nSize)px;'>
1920
+ @ <div class='statistics-report-graph-line' style='height:16px; width:%d(nSize)px;'>
18681921
@ </div></td>
18691922
@</tr>
1923
+
1924
+ /*
1925
+ Potential improvement: calculate the min/max event counts and
1926
+ use percent-based graph bars.
1927
+ */
1928
+ }
1929
+
1930
+ if(includeMonth && !showYearTotal && *zPrevYear){
1931
+ /* Add final year total separator. */
1932
+ rowClass = ++nRowNumber % 2;
1933
+ @ <tr class='row%d(rowClass)'>
1934
+ @ <td></td>
1935
+ @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
1936
+ @</tr>
18701937
}
1938
+
18711939
rowClass = ++nRowNumber % 2;
18721940
@ <tr class='row%d(rowClass)'>
1873
- @ <td colspan='3'>Total events: %d(nCommitCount)</td>
1941
+ @ <td colspan='3'>Total events: %d(nEventTotal)</td>
18741942
@ </tr>
18751943
@ </tbody></table>
18761944
db_finalize(&query);
1945
+}
1946
+
1947
+/*
1948
+** WEBPAGE: stats_report
1949
+**
1950
+** Shows activity reports for the repository.
1951
+**
1952
+** Query Parameters:
1953
+**
1954
+** view=REPORT_NAME Valid values: bymonth, byyear
1955
+** user=NAME Restricts statistics to the given user
1956
+*/
1957
+void stats_report_page(){
1958
+ HQuery url; /* URL for various branch links */
1959
+ char const * zView = PD("view","bymonth"); /* Which view/report to show. */
1960
+ char const *zUserName = P("user");
1961
+ url_initialize(&url, "stats_report");
1962
+ if(zUserName && *zUserName){
1963
+ url_add_parameter(&url,"user", zUserName);
1964
+ }
1965
+ timeline_submenu(&url, "By Year", "view", "byyear", 0);
1966
+ timeline_submenu(&url, "By Month", "view", "bymonth", 0);
1967
+ url_reset(&url);
1968
+ style_header("Activity Reports");
1969
+ if(0==fossil_strcmp(zView,"bymonth")){
1970
+ stats_report_bymonthyear(1, zUserName);
1971
+ }else if(0==fossil_strcmp(zView,"byyear")){
1972
+ stats_report_bymonthyear(0, zUserName);
1973
+ }else if(0==fossil_strcmp(zView,"byweek")){
1974
+ @ TODO: by-week report.
1975
+ }
18771976
style_footer();
18781977
}
18791978
--- src/timeline.c
+++ src/timeline.c
@@ -1826,53 +1826,152 @@
1826 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1827 }
1828 db_finalize(&q);
1829 style_footer();
1830 }
 
 
1831
1832 /*
1833 ** WEBPAGE: activity
1834 **
1835 ** Shows an activity report for the repository.
 
 
1836 */
1837 void activity_page(){
 
1838 Stmt query = empty_Stmt;
1839 int const nPixelsPerEvent = 1;
1840 int nRowNumber = 0;
1841 int nCommitCount = 0;
1842 int rowClass = 0;
1843 style_header("Repository Activity");
1844 db_prepare(&query,
1845 "SELECT substr(date(mtime),1,7) AS Month, "
1846 "count(*) AS Commits FROM event "
1847 "GROUP BY Month "
1848 "ORDER BY Month DESC", -1);
1849 @ <h1>Timeline Events by Month</h1>
1850 @ <table class='activity-table-commits-by-month' border='0' cellpadding='2' cellspacing='0'>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1851 @ <thead>
1852 @ <th>Year/Month</th>
1853 @ <th>Events</th>
1854 @ <th><!-- relative commits graph --></th>
1855 @ </thead><tbody>
 
1856 while( SQLITE_ROW == db_step(&query) ){
1857 char const * zMonth = db_column_text(&query, 0);
1858 int const nCount = db_column_int(&query, 1);
1859 int const nSize = nPixelsPerEvent * nCount;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1860 rowClass = ++nRowNumber % 2;
1861 nCommitCount += nCount;
 
1862 @<tr class='row%d(rowClass)'>
1863 @ <td>
1864 @ <a href="%s(g.zTop)/timeline?ym=%s(zMonth)&n=%d(nCount)" target="_new">%s(zMonth)</a>
 
 
 
 
1865 @ </td><td>%d(nCount)</td>
1866 @ <td>
1867 @ <div class='activity-graph-line' style='height:16px; width:%d(nSize)px;'>
1868 @ </div></td>
1869 @</tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1870 }
 
1871 rowClass = ++nRowNumber % 2;
1872 @ <tr class='row%d(rowClass)'>
1873 @ <td colspan='3'>Total events: %d(nCommitCount)</td>
1874 @ </tr>
1875 @ </tbody></table>
1876 db_finalize(&query);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1877 style_footer();
1878 }
1879
--- src/timeline.c
+++ src/timeline.c
@@ -1826,53 +1826,152 @@
1826 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1827 }
1828 db_finalize(&q);
1829 style_footer();
1830 }
1831
1832
1833
1834 /*
1835 ** Implements the "byyear" and "bymonth" reports for /stats_report.
1836 ** If includeMonth is true then it generates the "bymonth" report,
1837 ** else the "byyear" report. If zUserName is not NULL and not empty
1838 ** then the report is restricted to events created by the named user
1839 ** account.
1840 */
1841 static void stats_report_bymonthyear(char includeMonth,
1842 char const * zUserName){
1843 Stmt query = empty_Stmt;
1844 int const nPixelsPerEvent = 1; /* for sizing the "graph" part */
1845 int nRowNumber = 0; /* current TR number */
1846 int nEventTotal = 0; /* Total event count */
1847 int rowClass = 0; /* counter for alternating
1848 row colors */
1849 Blob sql = empty_blob; /* SQL */
1850 char const * zTimeLabel = includeMonth ? "Year/Month" : "Year";
1851 char zPrevYear[5] = {0}; /* For keeping track of when
1852 we change years while looping */
1853 int nEventsPerYear = 0; /* Total even count for the
1854 current year */
1855 char showYearTotal = 0; /* Flag telling us when to show
1856 the per-year event totals */
1857 Blob header = empty_blob; /* Page header text */
1858 blob_appendf(&header, "Timeline Events by %s", zTimeLabel);
1859 blob_appendf(&sql,
1860 "SELECT substr(date(mtime),1,%d) AS timeframe, "
1861 "count(*) AS eventCount "
1862 "FROM event ",
1863 includeMonth ? 7 : 4);
1864 if(zUserName&&*zUserName){
1865 blob_appendf(&sql, " WHERE user=%Q ", zUserName);
1866 blob_appendf(&header," for user %q", zUserName);
1867 }
1868 blob_append(&sql,
1869 " GROUP BY timeframe"
1870 " ORDER BY timeframe DESC",
1871 -1);
1872 db_prepare(&query, blob_str(&sql));
1873 blob_reset(&sql);
1874 @ <h1>%b(&header)</h1>
1875 @ <table class='statistics-report-table-events' border='0' cellpadding='2' cellspacing='0'>
1876 @ <thead>
1877 @ <th>%s(zTimeLabel)</th>
1878 @ <th>Events</th>
1879 @ <th><!-- relative commits graph --></th>
1880 @ </thead><tbody>
1881 blob_reset(&header);
1882 while( SQLITE_ROW == db_step(&query) ){
1883 char const * zTimeframe = db_column_text(&query, 0);
1884 int const nCount = db_column_int(&query, 1);
1885 int const nSize = 1 + ((nPixelsPerEvent * nCount)
1886 / (includeMonth ? 1 : 10));
1887 showYearTotal = 0;
1888 if(includeMonth){
1889 /* For Month/year view, add a separator for each distinct year. */
1890 if(!*zPrevYear ||
1891 (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
1892 showYearTotal = *zPrevYear;
1893 if(showYearTotal){
1894 rowClass = ++nRowNumber % 2;
1895 @ <tr class='row%d(rowClass)'>
1896 @ <td></td>
1897 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
1898 @</tr>
1899 }
1900 nEventsPerYear = 0;
1901 memcpy(zPrevYear,zTimeframe,4);
1902 rowClass = ++nRowNumber % 2;
1903 @ <tr class='row%d(rowClass)'>
1904 @ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
1905 @ </tr>
1906 }
1907 }
1908 rowClass = ++nRowNumber % 2;
1909 nEventTotal += nCount;
1910 nEventsPerYear += nCount;
1911 @<tr class='row%d(rowClass)'>
1912 @ <td>
1913 if(includeMonth){
1914 @ <a href="%s(g.zTop)/timeline?ym=%s(zTimeframe)&n=%d(nCount)" target="_new">%s(zTimeframe)</a>
1915 }else {
1916 @ %s(zTimeframe)
1917 }
1918 @ </td><td>%d(nCount)</td>
1919 @ <td>
1920 @ <div class='statistics-report-graph-line' style='height:16px; width:%d(nSize)px;'>
1921 @ </div></td>
1922 @</tr>
1923
1924 /*
1925 Potential improvement: calculate the min/max event counts and
1926 use percent-based graph bars.
1927 */
1928 }
1929
1930 if(includeMonth && !showYearTotal && *zPrevYear){
1931 /* Add final year total separator. */
1932 rowClass = ++nRowNumber % 2;
1933 @ <tr class='row%d(rowClass)'>
1934 @ <td></td>
1935 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
1936 @</tr>
1937 }
1938
1939 rowClass = ++nRowNumber % 2;
1940 @ <tr class='row%d(rowClass)'>
1941 @ <td colspan='3'>Total events: %d(nEventTotal)</td>
1942 @ </tr>
1943 @ </tbody></table>
1944 db_finalize(&query);
1945 }
1946
1947 /*
1948 ** WEBPAGE: stats_report
1949 **
1950 ** Shows activity reports for the repository.
1951 **
1952 ** Query Parameters:
1953 **
1954 ** view=REPORT_NAME Valid values: bymonth, byyear
1955 ** user=NAME Restricts statistics to the given user
1956 */
1957 void stats_report_page(){
1958 HQuery url; /* URL for various branch links */
1959 char const * zView = PD("view","bymonth"); /* Which view/report to show. */
1960 char const *zUserName = P("user");
1961 url_initialize(&url, "stats_report");
1962 if(zUserName && *zUserName){
1963 url_add_parameter(&url,"user", zUserName);
1964 }
1965 timeline_submenu(&url, "By Year", "view", "byyear", 0);
1966 timeline_submenu(&url, "By Month", "view", "bymonth", 0);
1967 url_reset(&url);
1968 style_header("Activity Reports");
1969 if(0==fossil_strcmp(zView,"bymonth")){
1970 stats_report_bymonthyear(1, zUserName);
1971 }else if(0==fossil_strcmp(zView,"byyear")){
1972 stats_report_bymonthyear(0, zUserName);
1973 }else if(0==fossil_strcmp(zView,"byweek")){
1974 @ TODO: by-week report.
1975 }
1976 style_footer();
1977 }
1978
+9
--- src/url.c
+++ src/url.c
@@ -371,10 +371,19 @@
371371
void url_initialize(HQuery *p, const char *zBase){
372372
blob_zero(&p->url);
373373
p->zBase = zBase;
374374
p->nParam = 0;
375375
}
376
+
377
+/*
378
+** Resets the given URL object, deallocating any memory
379
+** it uses.
380
+*/
381
+void url_reset(HQuery *p){
382
+ blob_reset(&p->url);
383
+ url_initialize(p, p->zBase);
384
+}
376385
377386
/*
378387
** Add a fixed parameter to an HQuery.
379388
*/
380389
void url_add_parameter(HQuery *p, const char *zName, const char *zValue){
381390
--- src/url.c
+++ src/url.c
@@ -371,10 +371,19 @@
371 void url_initialize(HQuery *p, const char *zBase){
372 blob_zero(&p->url);
373 p->zBase = zBase;
374 p->nParam = 0;
375 }
 
 
 
 
 
 
 
 
 
376
377 /*
378 ** Add a fixed parameter to an HQuery.
379 */
380 void url_add_parameter(HQuery *p, const char *zName, const char *zValue){
381
--- src/url.c
+++ src/url.c
@@ -371,10 +371,19 @@
371 void url_initialize(HQuery *p, const char *zBase){
372 blob_zero(&p->url);
373 p->zBase = zBase;
374 p->nParam = 0;
375 }
376
377 /*
378 ** Resets the given URL object, deallocating any memory
379 ** it uses.
380 */
381 void url_reset(HQuery *p){
382 blob_reset(&p->url);
383 url_initialize(p, p->zBase);
384 }
385
386 /*
387 ** Add a fixed parameter to an HQuery.
388 */
389 void url_add_parameter(HQuery *p, const char *zName, const char *zValue){
390

Keyboard Shortcuts

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