Fossil SCM
Add a human-readable description on each timeline. Add the "ancestors" and "decendents" links on the baseline information pages, making it easier to understand the context of a baseline.
Commit
e38c89130f8ee98be86a3a22c60bf65666487477
Parent
588bb7cd734d4c3…
2 files changed
+4
+36
-12
+4
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -331,10 +331,14 @@ | ||
| 331 | 331 | @ <tr><th>Record ID:</th><td>%d(rid)</td></tr> |
| 332 | 332 | } |
| 333 | 333 | @ <tr><th>Original User:</th><td>%h(db_column_text(&q, 2))</td></tr> |
| 334 | 334 | @ <tr><th>Original Comment:</th><td>%w(db_column_text(&q,3))</td></tr> |
| 335 | 335 | @ </td></tr> |
| 336 | + @ <tr><th>Timelines:</th><td> | |
| 337 | + @ <a href="%s(g.zBaseURL)/timeline?e=%d(rid)&r">ancestors</a> | |
| 338 | + @ | <a href="%s(g.zBaseURL)/timeline?e=%d(rid)&r&a">descendents</a> | |
| 339 | + @ </td></tr> | |
| 336 | 340 | @ <tr><th>Commands:</th> |
| 337 | 341 | @ <td> |
| 338 | 342 | @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a> |
| 339 | 343 | @ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a> |
| 340 | 344 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 341 | 345 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -331,10 +331,14 @@ | |
| 331 | @ <tr><th>Record ID:</th><td>%d(rid)</td></tr> |
| 332 | } |
| 333 | @ <tr><th>Original User:</th><td>%h(db_column_text(&q, 2))</td></tr> |
| 334 | @ <tr><th>Original Comment:</th><td>%w(db_column_text(&q,3))</td></tr> |
| 335 | @ </td></tr> |
| 336 | @ <tr><th>Commands:</th> |
| 337 | @ <td> |
| 338 | @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a> |
| 339 | @ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a> |
| 340 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 341 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -331,10 +331,14 @@ | |
| 331 | @ <tr><th>Record ID:</th><td>%d(rid)</td></tr> |
| 332 | } |
| 333 | @ <tr><th>Original User:</th><td>%h(db_column_text(&q, 2))</td></tr> |
| 334 | @ <tr><th>Original Comment:</th><td>%w(db_column_text(&q,3))</td></tr> |
| 335 | @ </td></tr> |
| 336 | @ <tr><th>Timelines:</th><td> |
| 337 | @ <a href="%s(g.zBaseURL)/timeline?e=%d(rid)&r">ancestors</a> |
| 338 | @ | <a href="%s(g.zBaseURL)/timeline?e=%d(rid)&r&a">descendents</a> |
| 339 | @ </td></tr> |
| 340 | @ <tr><th>Commands:</th> |
| 341 | @ <td> |
| 342 | @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a> |
| 343 | @ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a> |
| 344 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 345 |
+36
-12
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -251,24 +251,26 @@ | ||
| 251 | 251 | ** r show only related events. dflt: false |
| 252 | 252 | ** y=TYPE show only TYPE ('ci' or 'w') dflt: nil |
| 253 | 253 | ** s show the SQL dflt: nil |
| 254 | 254 | */ |
| 255 | 255 | void page_timeline(void){ |
| 256 | - Stmt q; | |
| 257 | - Blob sql; | |
| 258 | - char *zSQL; | |
| 256 | + Stmt q; | |
| 257 | + Blob sql; /* text of SQL used to generate timeline */ | |
| 258 | + char *zSQL; /* Rendered copy of sql */ | |
| 259 | 259 | Blob scriptInit; |
| 260 | 260 | char zDate[100]; |
| 261 | - const char *zStart = P("d"); | |
| 262 | - int nEntry = atoi(PD("n","20")); | |
| 263 | - const char *zUser = P("u"); | |
| 264 | - int objid = atoi(PD("e","0")); | |
| 265 | - int relatedEvents = P("r")!=0; | |
| 266 | - int afterFlag = P("a")!=0; | |
| 267 | - const char *zType = P("y"); | |
| 268 | - int firstEvent; | |
| 269 | - int lastEvent; | |
| 261 | + const char *zStart = P("d"); /* Starting date */ | |
| 262 | + int nEntry = atoi(PD("n","20")); /* Max number of entries on timeline */ | |
| 263 | + const char *zUser = P("u"); /* All entries by this user if not NULL */ | |
| 264 | + int objid = atoi(PD("e","0")); /* Entries related to this event */ | |
| 265 | + int relatedEvents = P("r")!=0; /* Must be directly related to of objid */ | |
| 266 | + int afterFlag = P("a")!=0; /* After objid if true */ | |
| 267 | + const char *zType = P("y"); /* Type of events. All if NULL */ | |
| 268 | + int firstEvent; /* First event displayed */ | |
| 269 | + int lastEvent; /* Last event displayed */ | |
| 270 | + Blob desc; /* Human readable description of the timeline */ | |
| 271 | + const char *zEType; /* Human readable event type */ | |
| 270 | 272 | |
| 271 | 273 | /* To view the timeline, must have permission to read project data. |
| 272 | 274 | */ |
| 273 | 275 | login_check_credentials(); |
| 274 | 276 | if( !g.okRead ){ login_needed(); return; } |
| @@ -280,16 +282,25 @@ | ||
| 280 | 282 | " AND cap LIKE '%%h%%'") ){ |
| 281 | 283 | @ <p><b>Note:</b> You will be able to access <u>much</u> more |
| 282 | 284 | @ historical information if you <a href="%s(g.zTop)/login">login</a>.</p> |
| 283 | 285 | } |
| 284 | 286 | blob_zero(&sql); |
| 287 | + blob_zero(&desc); | |
| 285 | 288 | blob_append(&sql, timeline_query_for_www(), -1); |
| 289 | + zEType = "events"; | |
| 286 | 290 | if( zType ){ |
| 287 | 291 | blob_appendf(&sql, " AND event.type=%Q", zType); |
| 292 | + if( zType[0]=='c' ){ | |
| 293 | + zEType = "checkins"; | |
| 294 | + }else if( zType[0]=='w' ){ | |
| 295 | + zEType = "wiki edits"; | |
| 296 | + } | |
| 288 | 297 | } |
| 298 | + blob_appendf(&desc, "Timeline of up to %d %s", nEntry, zEType); | |
| 289 | 299 | if( zUser ){ |
| 290 | 300 | blob_appendf(&sql, " AND event.user=%Q", zUser); |
| 301 | + blob_appendf(&desc, " by user %h", zUser); | |
| 291 | 302 | } |
| 292 | 303 | if( objid ){ |
| 293 | 304 | char *z = db_text(0, "SELECT datetime(event.mtime, 'localtime') FROM event" |
| 294 | 305 | " WHERE objid=%d", objid); |
| 295 | 306 | if( z ){ |
| @@ -300,20 +311,31 @@ | ||
| 300 | 311 | while( isspace(zStart[0]) ){ zStart++; } |
| 301 | 312 | if( zStart[0] ){ |
| 302 | 313 | blob_appendf(&sql, |
| 303 | 314 | " AND event.mtime %s (SELECT julianday(%Q, 'utc'))", |
| 304 | 315 | afterFlag ? ">=" : "<=", zStart); |
| 316 | + blob_appendf(&desc, " occurring on or %s %h", | |
| 317 | + afterFlag ? "after": "before", | |
| 318 | + zStart); | |
| 305 | 319 | } |
| 306 | 320 | } |
| 307 | 321 | if( relatedEvents && objid ){ |
| 322 | + char *zUuid; | |
| 308 | 323 | db_multi_exec( |
| 309 | 324 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" |
| 310 | 325 | ); |
| 326 | + zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", objid); | |
| 311 | 327 | if( afterFlag ){ |
| 312 | 328 | compute_descendents(objid, nEntry); |
| 329 | + blob_appendf(&desc, | |
| 330 | + " and decended from <a href='%s/vinfo/%d'>[%.10s]</a>", | |
| 331 | + g.zBaseURL, objid, zUuid); | |
| 313 | 332 | }else{ |
| 314 | 333 | compute_ancestors(objid, nEntry); |
| 334 | + blob_appendf(&desc, | |
| 335 | + " and a ancestor of <a href='%s/vinfo/%d'>[%.10s]</a>", | |
| 336 | + g.zBaseURL, objid, zUuid); | |
| 315 | 337 | } |
| 316 | 338 | blob_append(&sql, " AND event.objid IN ok", -1); |
| 317 | 339 | } |
| 318 | 340 | if( afterFlag ){ |
| 319 | 341 | blob_appendf(&sql, " ORDER BY event.mtime ASC LIMIT %d", |
| @@ -328,10 +350,12 @@ | ||
| 328 | 350 | } |
| 329 | 351 | db_prepare(&q, zSQL); |
| 330 | 352 | if( P("s")!=0 ){ |
| 331 | 353 | @ <hr><p>%h(zSQL)</p><hr> |
| 332 | 354 | } |
| 355 | + @ <h2>%b(&desc)</h2> | |
| 356 | + blob_reset(&desc); | |
| 333 | 357 | blob_zero(&sql); |
| 334 | 358 | if( afterFlag ){ |
| 335 | 359 | free(zSQL); |
| 336 | 360 | } |
| 337 | 361 | zDate[0] = 0; |
| 338 | 362 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -251,24 +251,26 @@ | |
| 251 | ** r show only related events. dflt: false |
| 252 | ** y=TYPE show only TYPE ('ci' or 'w') dflt: nil |
| 253 | ** s show the SQL dflt: nil |
| 254 | */ |
| 255 | void page_timeline(void){ |
| 256 | Stmt q; |
| 257 | Blob sql; |
| 258 | char *zSQL; |
| 259 | Blob scriptInit; |
| 260 | char zDate[100]; |
| 261 | const char *zStart = P("d"); |
| 262 | int nEntry = atoi(PD("n","20")); |
| 263 | const char *zUser = P("u"); |
| 264 | int objid = atoi(PD("e","0")); |
| 265 | int relatedEvents = P("r")!=0; |
| 266 | int afterFlag = P("a")!=0; |
| 267 | const char *zType = P("y"); |
| 268 | int firstEvent; |
| 269 | int lastEvent; |
| 270 | |
| 271 | /* To view the timeline, must have permission to read project data. |
| 272 | */ |
| 273 | login_check_credentials(); |
| 274 | if( !g.okRead ){ login_needed(); return; } |
| @@ -280,16 +282,25 @@ | |
| 280 | " AND cap LIKE '%%h%%'") ){ |
| 281 | @ <p><b>Note:</b> You will be able to access <u>much</u> more |
| 282 | @ historical information if you <a href="%s(g.zTop)/login">login</a>.</p> |
| 283 | } |
| 284 | blob_zero(&sql); |
| 285 | blob_append(&sql, timeline_query_for_www(), -1); |
| 286 | if( zType ){ |
| 287 | blob_appendf(&sql, " AND event.type=%Q", zType); |
| 288 | } |
| 289 | if( zUser ){ |
| 290 | blob_appendf(&sql, " AND event.user=%Q", zUser); |
| 291 | } |
| 292 | if( objid ){ |
| 293 | char *z = db_text(0, "SELECT datetime(event.mtime, 'localtime') FROM event" |
| 294 | " WHERE objid=%d", objid); |
| 295 | if( z ){ |
| @@ -300,20 +311,31 @@ | |
| 300 | while( isspace(zStart[0]) ){ zStart++; } |
| 301 | if( zStart[0] ){ |
| 302 | blob_appendf(&sql, |
| 303 | " AND event.mtime %s (SELECT julianday(%Q, 'utc'))", |
| 304 | afterFlag ? ">=" : "<=", zStart); |
| 305 | } |
| 306 | } |
| 307 | if( relatedEvents && objid ){ |
| 308 | db_multi_exec( |
| 309 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" |
| 310 | ); |
| 311 | if( afterFlag ){ |
| 312 | compute_descendents(objid, nEntry); |
| 313 | }else{ |
| 314 | compute_ancestors(objid, nEntry); |
| 315 | } |
| 316 | blob_append(&sql, " AND event.objid IN ok", -1); |
| 317 | } |
| 318 | if( afterFlag ){ |
| 319 | blob_appendf(&sql, " ORDER BY event.mtime ASC LIMIT %d", |
| @@ -328,10 +350,12 @@ | |
| 328 | } |
| 329 | db_prepare(&q, zSQL); |
| 330 | if( P("s")!=0 ){ |
| 331 | @ <hr><p>%h(zSQL)</p><hr> |
| 332 | } |
| 333 | blob_zero(&sql); |
| 334 | if( afterFlag ){ |
| 335 | free(zSQL); |
| 336 | } |
| 337 | zDate[0] = 0; |
| 338 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -251,24 +251,26 @@ | |
| 251 | ** r show only related events. dflt: false |
| 252 | ** y=TYPE show only TYPE ('ci' or 'w') dflt: nil |
| 253 | ** s show the SQL dflt: nil |
| 254 | */ |
| 255 | void page_timeline(void){ |
| 256 | Stmt q; |
| 257 | Blob sql; /* text of SQL used to generate timeline */ |
| 258 | char *zSQL; /* Rendered copy of sql */ |
| 259 | Blob scriptInit; |
| 260 | char zDate[100]; |
| 261 | const char *zStart = P("d"); /* Starting date */ |
| 262 | int nEntry = atoi(PD("n","20")); /* Max number of entries on timeline */ |
| 263 | const char *zUser = P("u"); /* All entries by this user if not NULL */ |
| 264 | int objid = atoi(PD("e","0")); /* Entries related to this event */ |
| 265 | int relatedEvents = P("r")!=0; /* Must be directly related to of objid */ |
| 266 | int afterFlag = P("a")!=0; /* After objid if true */ |
| 267 | const char *zType = P("y"); /* Type of events. All if NULL */ |
| 268 | int firstEvent; /* First event displayed */ |
| 269 | int lastEvent; /* Last event displayed */ |
| 270 | Blob desc; /* Human readable description of the timeline */ |
| 271 | const char *zEType; /* Human readable event type */ |
| 272 | |
| 273 | /* To view the timeline, must have permission to read project data. |
| 274 | */ |
| 275 | login_check_credentials(); |
| 276 | if( !g.okRead ){ login_needed(); return; } |
| @@ -280,16 +282,25 @@ | |
| 282 | " AND cap LIKE '%%h%%'") ){ |
| 283 | @ <p><b>Note:</b> You will be able to access <u>much</u> more |
| 284 | @ historical information if you <a href="%s(g.zTop)/login">login</a>.</p> |
| 285 | } |
| 286 | blob_zero(&sql); |
| 287 | blob_zero(&desc); |
| 288 | blob_append(&sql, timeline_query_for_www(), -1); |
| 289 | zEType = "events"; |
| 290 | if( zType ){ |
| 291 | blob_appendf(&sql, " AND event.type=%Q", zType); |
| 292 | if( zType[0]=='c' ){ |
| 293 | zEType = "checkins"; |
| 294 | }else if( zType[0]=='w' ){ |
| 295 | zEType = "wiki edits"; |
| 296 | } |
| 297 | } |
| 298 | blob_appendf(&desc, "Timeline of up to %d %s", nEntry, zEType); |
| 299 | if( zUser ){ |
| 300 | blob_appendf(&sql, " AND event.user=%Q", zUser); |
| 301 | blob_appendf(&desc, " by user %h", zUser); |
| 302 | } |
| 303 | if( objid ){ |
| 304 | char *z = db_text(0, "SELECT datetime(event.mtime, 'localtime') FROM event" |
| 305 | " WHERE objid=%d", objid); |
| 306 | if( z ){ |
| @@ -300,20 +311,31 @@ | |
| 311 | while( isspace(zStart[0]) ){ zStart++; } |
| 312 | if( zStart[0] ){ |
| 313 | blob_appendf(&sql, |
| 314 | " AND event.mtime %s (SELECT julianday(%Q, 'utc'))", |
| 315 | afterFlag ? ">=" : "<=", zStart); |
| 316 | blob_appendf(&desc, " occurring on or %s %h", |
| 317 | afterFlag ? "after": "before", |
| 318 | zStart); |
| 319 | } |
| 320 | } |
| 321 | if( relatedEvents && objid ){ |
| 322 | char *zUuid; |
| 323 | db_multi_exec( |
| 324 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" |
| 325 | ); |
| 326 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", objid); |
| 327 | if( afterFlag ){ |
| 328 | compute_descendents(objid, nEntry); |
| 329 | blob_appendf(&desc, |
| 330 | " and decended from <a href='%s/vinfo/%d'>[%.10s]</a>", |
| 331 | g.zBaseURL, objid, zUuid); |
| 332 | }else{ |
| 333 | compute_ancestors(objid, nEntry); |
| 334 | blob_appendf(&desc, |
| 335 | " and a ancestor of <a href='%s/vinfo/%d'>[%.10s]</a>", |
| 336 | g.zBaseURL, objid, zUuid); |
| 337 | } |
| 338 | blob_append(&sql, " AND event.objid IN ok", -1); |
| 339 | } |
| 340 | if( afterFlag ){ |
| 341 | blob_appendf(&sql, " ORDER BY event.mtime ASC LIMIT %d", |
| @@ -328,10 +350,12 @@ | |
| 350 | } |
| 351 | db_prepare(&q, zSQL); |
| 352 | if( P("s")!=0 ){ |
| 353 | @ <hr><p>%h(zSQL)</p><hr> |
| 354 | } |
| 355 | @ <h2>%b(&desc)</h2> |
| 356 | blob_reset(&desc); |
| 357 | blob_zero(&sql); |
| 358 | if( afterFlag ){ |
| 359 | free(zSQL); |
| 360 | } |
| 361 | zDate[0] = 0; |
| 362 |