@@ -23,8 +23,9 @@
**
** This file contains code to implement the timeline web page
**
*/
+#include <string.h>
#include "config.h"
#include "timeline.h"
/*
@@ -88,14 +89,20 @@
** 7. True if is a leaf
*/
void www_print_timeline(
Stmt *pQuery,
- char *zLastDate,
+ int *pFirstEvent,
+ int *pLastEvent,
int (*xCallback)(int, Blob*),
Blob *pArg
){
char zPrevDate[20];
+ int cnt = 0;
zPrevDate[0] = 0;
+ db_multi_exec(
+ "CREATE TEMP TABLE IF NOT EXISTS seen(rid INTEGER PRIMARY KEY);"
+ "DELETE FROM seen;"
+ );
@ <table cellspacing=0 border=0 cellpadding=0>
while( db_step(pQuery)==SQLITE_ROW ){
int rid = db_column_int(pQuery, 0);
const char *zUuid = db_column_text(pQuery, 1);
@@ -102,8 +109,15 @@
int nPChild = db_column_int(pQuery, 5);
int nParent = db_column_int(pQuery, 6);
int isLeaf = db_column_int(pQuery, 7);
const char *zDate = db_column_text(pQuery, 2);
+ if( cnt==0 && pFirstEvent ){
+ *pFirstEvent = rid;
+ }
+ if( pLastEvent ){
+ *pLastEvent = rid;
+ }
+ db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
if( xCallback ){
xCallback(rid, pArg);
}
if( memcmp(zDate, zPrevDate, 10) ){
@@ -133,11 +147,8 @@
@ <b>Leaf</b>
}
@ %h(db_column_text(pQuery,3))
@ (by %h(db_column_text(pQuery,4)))</td></tr>
- if( zLastDate ){
- strcpy(zLastDate, zDate);
- }
}
@ </table>
}
@@ -173,16 +184,31 @@
}
/*
** WEBPAGE: timeline
+**
+** Query parameters:
+**
+** d=STARTDATE date in iso8601 notation. dflt: newest event
+** n=INTEGER number of events to show. dflt: 25
+** e=INTEGER starting event id. dflt: nil
+** u=NAME show only events from user. dflt: nil
+** a show events after and including. dflt: false
+** r show only related events. dflt: false
*/
void page_timeline(void){
Stmt q;
char *zSQL;
Blob scriptInit;
char zDate[100];
const char *zStart = P("d");
- int nEntry = atoi(PD("n","25"));
+ int nEntry = atoi(PD("n","20"));
+ const char *zUser = P("u");
+ int objid = atoi(PD("e","0"));
+ int relatedEvents = P("r")!=0;
+ int afterFlag = P("a")!=0;
+ int firstEvent;
+ int lastEvent;
/* To view the timeline, must have permission to read project data.
*/
login_check_credentials();
@@ -203,21 +229,44 @@
" NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid)"
" FROM event, blob"
" WHERE event.type='ci' AND blob.rid=event.objid"
);
+ if( zUser ){
+ zSQL = mprintf("%z AND event.user=%Q", zSQL, zUser);
+ }
+ if( objid ){
+ char *z = db_text(0, "SELECT datetime(event.mtime) FROM event"
+ " WHERE objid=%d", objid);
+ if( z ){
+ zStart = z;
+ }
+ }
if( zStart ){
while( isspace(zStart[0]) ){ zStart++; }
if( zStart[0] ){
- zSQL = mprintf("%z AND event.mtime<=julianday(%Q, 'localtime')",
- zSQL, zStart);
+ zSQL = mprintf("%z AND event.mtime %s julianday(%Q, 'localtime')",
+ zSQL, afterFlag ? ">=" : "<=", zStart);
+ }
+ }
+ if( relatedEvents && objid ){
+ db_multi_exec(
+ "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
+ );
+ if( afterFlag ){
+ compute_descendents(objid, nEntry);
+ }else{
+ compute_ancestors(objid, nEntry);
}
+ zSQL = mprintf("%z AND event.objid IN ok", zSQL);
}
zSQL = mprintf("%z ORDER BY event.mtime DESC LIMIT %d", zSQL, nEntry);
db_prepare(&q, zSQL);
free(zSQL);
zDate[0] = 0;
blob_zero(&scriptInit);
- www_print_timeline(&q, zDate, save_parentage_javascript, &scriptInit);
+ zDate[0] = 0;
+ www_print_timeline(&q, &firstEvent, &lastEvent,
+ save_parentage_javascript, &scriptInit);
db_finalize(&q);
if( zStart==0 ){
zStart = zDate;
}
@@ -351,47 +400,106 @@
/*
** COMMAND: timeline
**
-** Usage: %fossil timeline ?DATETIME? ?-n|--count N?
+** Usage: %fossil timeline ?WHEN? ?UUID|DATETIME? ?-n|--count N?
**
** Print a summary of activity going backwards in date and time
** specified or from the current date and time if no arguments
-** are given. Show as many as N (default 20) check-ins.
+** are given. Show as many as N (default 20) check-ins. The
+** WHEN argument can be any unique abbreviation of one of these
+** keywords:
+**
+** before
+** after
+** descendents | children
+** ancestors | parents
**
-** The date and time should be in the ISO8601 format. For
-** examples: "2007-08-18 07:21:21". The time may be omitted.
-** Times are according to the local timezone.
+** The UUID can be any unique prefix of 4 characters or more.
+** The DATETIME should be in the ISO8601 format. For
+** examples: "2007-08-18 07:21:21". You can also say "current"
+** for the current version or "now" for the current time.
*/
void timeline_cmd(void){
Stmt q;
- int n;
+ int n, k;
const char *zCount;
+ char *zOrigin;
char *zDate;
+ char *zSQL;
+ int objid = 0;
+ Blob uuid;
+ int mode = 1 ; /* 1: before 2:after 3:children 4:parents */
db_find_and_open_repository();
zCount = find_option("n","count",1);
if( zCount ){
n = atoi(zCount);
}else{
n = 20;
}
- if( g.argc!=2 && g.argc!=3 ){
- usage("YYYY-MM-DDtHH:MM:SS");
+ if( g.argc==4 ){
+ k = strlen(g.argv[2]);
+ if( strncmp(g.argv[2],"before",k)==0 ){
+ mode = 1;
+ }else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){
+ mode = 2;
+ }else if( strncmp(g.argv[2],"descendents",k)==0 ){
+ mode = 3;
+ }else if( strncmp(g.argv[2],"children",k)==0 ){
+ mode = 3;
+ }else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){
+ mode = 4;
+ }else if( strncmp(g.argv[2],"parents",k)==0 ){
+ mode = 4;
+ }else{
+ usage("?WHEN? ?UUID|DATETIME?");
+ }
+ zOrigin = g.argv[3];
+ }else if( g.argc==3 ){
+ zOrigin = g.argv[2];
+ }else{
+ zOrigin = "now";
}
- if( g.argc==3 ){
- zDate = g.argv[2];
+ k = strlen(zOrigin);
+ blob_zero(&uuid);
+ blob_append(&uuid, zOrigin, -1);
+ if( strcmp(zOrigin, "now")==0 ){
+ if( mode==3 || mode==4 ){
+ fossil_fatal("cannot compute descendents or ancestors of a date");
+ }
+ zDate = mprintf("(SELECT julianday('now','utc'))");
+ }else if( strncmp(zOrigin, "current", k)==0 ){
+ objid = db_lget_int("checkout",0);
+ zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid);
+ }else if( name_to_uuid(&uuid, 0)==0 ){
+ objid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid);
+ zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid);
}else{
- zDate = "now";
+ if( mode==3 || mode==4 ){
+ fossil_fatal("cannot compute descendents or ancestors of a date");
+ }
+ zDate = mprintf("(SELECT julianday(%Q, 'utc'))", zOrigin);
}
- db_prepare(&q,
+ zSQL = mprintf(
"SELECT blob.rid, uuid, datetime(event.mtime,'localtime'),"
" comment || ' (by ' || user || ')',"
" (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim),"
" (SELECT count(*) FROM plink WHERE cid=blob.rid)"
" FROM event, blob"
" WHERE event.type='ci' AND blob.rid=event.objid"
- " AND event.mtime<=(SELECT julianday(%Q,'utc'))"
- " ORDER BY event.mtime DESC", zDate
+ " AND event.mtime %s %s",
+ (mode==1 || mode==4) ? "<=" : ">=", zDate
);
+ if( mode==3 || mode==4 ){
+ db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
+ if( mode==3 ){
+ compute_descendents(objid, n);
+ }else{
+ compute_ancestors(objid, n);
+ }
+ zSQL = mprintf("%z AND blob.rid IN ok", zSQL);
+ }
+ zSQL = mprintf("%z ORDER BY event.mtime DESC", zSQL);
+ db_prepare(&q, zSQL);
print_timeline(&q, n);
db_finalize(&q);
}