| | @@ -401,19 +401,25 @@ |
| 401 | 401 | ** rn=N Ticket report number. (required) |
| 402 | 402 | ** t=TITLE Title of the report format |
| 403 | 403 | ** w=USER Owner of the report format |
| 404 | 404 | ** s=SQL SQL text used to implement the report |
| 405 | 405 | ** k=KEY Color key |
| 406 | +** d=DESC Optional descriptive text |
| 407 | +** m=MIMETYPE Mimetype for DESC |
| 408 | +** x=TAG Symbolic name for the report |
| 406 | 409 | */ |
| 407 | 410 | void view_edit(void){ |
| 408 | 411 | int rn; |
| 409 | | - const char *zTitle; |
| 412 | + const char *zTitle; /* Title of the report */ |
| 410 | 413 | const char *z; |
| 411 | | - const char *zOwner; |
| 412 | | - const char *zClrKey; |
| 413 | | - char *zSQL; |
| 414 | | - char *zErr = 0; |
| 414 | + const char *zOwner; /* Owner of the report */ |
| 415 | + const char *zClrKey; /* Color key - used to add colors to lines */ |
| 416 | + char *zSQL; /* The SQL text that gnerates the report */ |
| 417 | + char *zErr = 0; /* An error message */ |
| 418 | + const char *zDesc; /* Extra descriptive text about the report */ |
| 419 | + const char *zMimetype; /* Mimetype for zDesc */ |
| 420 | + const char *zTag; /* Symbolic name for this report */ |
| 415 | 421 | int dflt = P("dflt") ? 1 : 0; |
| 416 | 422 | |
| 417 | 423 | login_check_credentials(); |
| 418 | 424 | if( !g.perm.TktFmt ){ |
| 419 | 425 | login_needed(g.anon.TktFmt); |
| | @@ -425,10 +431,14 @@ |
| 425 | 431 | zTitle = P("t"); |
| 426 | 432 | zOwner = PD("w",g.zLogin); |
| 427 | 433 | z = P("s"); |
| 428 | 434 | zSQL = z ? trim_string(z) : 0; |
| 429 | 435 | zClrKey = trim_string(PD("k","")); |
| 436 | + zDesc = trim_string(PD("d","")); |
| 437 | + zMimetype = P("m"); |
| 438 | + zTag = P("x"); |
| 439 | + report_update_reportfmt_table(); |
| 430 | 440 | if( rn>0 && P("del2") ){ |
| 431 | 441 | login_verify_csrf_secret(); |
| 432 | 442 | db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn); |
| 433 | 443 | cgi_redirect("reportlist"); |
| 434 | 444 | return; |
| | @@ -470,18 +480,26 @@ |
| 470 | 480 | ){ |
| 471 | 481 | zErr = mprintf("There is already another report named \"%h\"", zTitle); |
| 472 | 482 | } |
| 473 | 483 | if( zErr==0 ){ |
| 474 | 484 | login_verify_csrf_secret(); |
| 485 | + if( zTag && zTag[0]==0 ) zTag = 0; |
| 486 | + if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 487 | + if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 475 | 488 | if( rn>0 ){ |
| 476 | | - db_multi_exec("UPDATE reportfmt SET title=%Q, sqlcode=%Q," |
| 477 | | - " owner=%Q, cols=%Q, mtime=now() WHERE rn=%d", |
| 478 | | - zTitle, zSQL, zOwner, zClrKey, rn); |
| 489 | + db_multi_exec( |
| 490 | + "UPDATE reportfmt SET title=%Q, sqlcode=%Q," |
| 491 | + " owner=%Q, cols=%Q, mtime=now(), " |
| 492 | + " jx=json_patch(jx,json_object('desc',%Q,'descmt',%Q,'tag',%Q))" |
| 493 | + " WHERE rn=%d", |
| 494 | + zTitle, zSQL, zOwner, zClrKey, zDesc, zMimetype, zTag, rn); |
| 479 | 495 | }else{ |
| 480 | | - db_multi_exec("INSERT INTO reportfmt(title,sqlcode,owner,cols,mtime) " |
| 481 | | - "VALUES(%Q,%Q,%Q,%Q,now())", |
| 482 | | - zTitle, zSQL, zOwner, zClrKey); |
| 496 | + db_multi_exec( |
| 497 | + "INSERT INTO reportfmt(title,sqlcode,owner,cols,mtime,jx) " |
| 498 | + "VALUES(%Q,%Q,%Q,%Q,now()," |
| 499 | + "json_object('desc',%Q,'descmt',%Q,'tag',%Q))", |
| 500 | + zTitle, zSQL, zOwner, zClrKey, zDesc, zMimetype, zTag); |
| 483 | 501 | rn = db_last_insert_rowid(); |
| 484 | 502 | } |
| 485 | 503 | if( dflt ){ |
| 486 | 504 | db_set("ticket-default-report", zTitle, 0); |
| 487 | 505 | }else{ |
| | @@ -497,21 +515,36 @@ |
| 497 | 515 | zTitle = ""; |
| 498 | 516 | zSQL = ticket_report_template(); |
| 499 | 517 | zClrKey = ticket_key_template(); |
| 500 | 518 | }else{ |
| 501 | 519 | Stmt q; |
| 502 | | - db_prepare(&q, "SELECT title, sqlcode, owner, cols " |
| 520 | + int hasJx; |
| 521 | + zDesc = 0; |
| 522 | + zMimetype = 0; |
| 523 | + zTag = 0; |
| 524 | + db_prepare(&q, "SELECT title, sqlcode, owner, cols, json_valid(jx) " |
| 503 | 525 | "FROM reportfmt WHERE rn=%d",rn); |
| 504 | 526 | if( db_step(&q)==SQLITE_ROW ){ |
| 505 | 527 | char *defaultReport = db_get("ticket-default-report", 0); |
| 506 | 528 | zTitle = db_column_malloc(&q, 0); |
| 507 | 529 | zSQL = db_column_malloc(&q, 1); |
| 508 | 530 | zOwner = db_column_malloc(&q, 2); |
| 509 | 531 | zClrKey = db_column_malloc(&q, 3); |
| 510 | 532 | dflt = fossil_strcmp(zTitle, defaultReport)==0; |
| 533 | + hasJx = db_column_int(&q, 4); |
| 511 | 534 | } |
| 512 | 535 | db_finalize(&q); |
| 536 | + if( hasJx ){ |
| 537 | + db_prepare(&q, "SELECT jx->>'desc', jx->>'descmt', jx->>'tag'" |
| 538 | + " FROM reportfmt WHERE rn=%d", rn); |
| 539 | + if( db_step(&q)==SQLITE_ROW ){ |
| 540 | + zDesc = db_column_malloc(&q, 0); |
| 541 | + zMimetype = db_column_malloc(&q, 1); |
| 542 | + zTag = db_column_malloc(&q, 2); |
| 543 | + } |
| 544 | + db_finalize(&q); |
| 545 | + } |
| 513 | 546 | if( P("copy") ){ |
| 514 | 547 | rn = 0; |
| 515 | 548 | zTitle = mprintf("Copy Of %s", zTitle); |
| 516 | 549 | zOwner = g.zLogin; |
| 517 | 550 | } |
| | @@ -535,19 +568,33 @@ |
| 535 | 568 | login_insert_csrf_secret(); |
| 536 | 569 | if( g.perm.Admin ){ |
| 537 | 570 | @ <p>Report owner: |
| 538 | 571 | @ <input type="text" name="w" size="20" value="%h(zOwner)" /> |
| 539 | 572 | @ </p> |
| 573 | + @ <p>Tag: |
| 574 | + @ <input type="text" name="x" size="20" value="%h(zTag?zTag:"")" /> |
| 575 | + @ </p> |
| 540 | 576 | } else { |
| 541 | 577 | @ <input type="hidden" name="w" value="%h(zOwner)" /> |
| 578 | + if( zTag && zTag[0] ){ |
| 579 | + @ <input type="hidden" name="x" value="%h(zTag)" /> |
| 580 | + } |
| 542 | 581 | } |
| 543 | 582 | @ <p>Enter an optional color key in the following box. (If blank, no |
| 544 | 583 | @ color key is displayed.) Each line contains the text for a single |
| 545 | 584 | @ entry in the key. The first token of each line is the background |
| 546 | 585 | @ color for that line.<br /> |
| 547 | 586 | @ <textarea name="k" rows="8" cols="50">%h(zClrKey)</textarea> |
| 548 | 587 | @ </p> |
| 588 | + |
| 589 | + @ <p>Optional human-readable description for this report<br /> |
| 590 | + @ %z(href("%R/markup_help"))Markup style</a>: |
| 591 | + mimetype_option_menu(zMimetype, "m"); |
| 592 | + @ <br><textarea aria-label="Description:" name="d" class="wikiedit" \ |
| 593 | + @ cols="80" rows="15" wrap="virtual">%h(zDesc)</textarea> |
| 594 | + @ </p> |
| 595 | + |
| 549 | 596 | @ <p><label><input type="checkbox" name="dflt" %s(dflt?"checked":"")> \ |
| 550 | 597 | @ Make this the default report</label></p> |
| 551 | 598 | if( !g.perm.Admin && fossil_strcmp(zOwner,g.zLogin)!=0 ){ |
| 552 | 599 | @ <p>This report format is owned by %h(zOwner). You are not allowed |
| 553 | 600 | @ to change it.</p> |
| | @@ -1039,29 +1086,33 @@ |
| 1039 | 1086 | int rn, rc; |
| 1040 | 1087 | char *zSql; |
| 1041 | 1088 | char *zTitle; |
| 1042 | 1089 | char *zOwner; |
| 1043 | 1090 | char *zClrKey; |
| 1091 | + char *zDesc; |
| 1092 | + char *zMimetype; |
| 1044 | 1093 | int tabs; |
| 1045 | 1094 | Stmt q; |
| 1046 | 1095 | char *zErr1 = 0; |
| 1047 | 1096 | char *zErr2 = 0; |
| 1048 | 1097 | |
| 1049 | 1098 | login_check_credentials(); |
| 1050 | 1099 | if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; } |
| 1051 | 1100 | tabs = P("tablist")!=0; |
| 1052 | 1101 | db_prepare(&q, |
| 1053 | | - "SELECT title, sqlcode, owner, cols, rn FROM reportfmt WHERE rn=%d", |
| 1102 | + "SELECT title, sqlcode, owner, cols, rn, jx->>'desc', jx->>'descmt'" |
| 1103 | + " FROM reportfmt WHERE rn=%d", |
| 1054 | 1104 | atoi(PD("rn","0"))); |
| 1055 | 1105 | rc = db_step(&q); |
| 1056 | 1106 | if( rc!=SQLITE_ROW ){ |
| 1057 | 1107 | const char *titleSearch = |
| 1058 | 1108 | defaultTitleSearch==0 || trim_string(defaultTitleSearch)[0]==0 ? |
| 1059 | 1109 | P("title") : defaultTitleSearch; |
| 1060 | 1110 | db_finalize(&q); |
| 1061 | 1111 | db_prepare(&q, |
| 1062 | | - "SELECT title, sqlcode, owner, cols, rn FROM reportfmt WHERE title GLOB %Q", |
| 1112 | + "SELECT title, sqlcode, owner, cols, rn, jx->>'desc', jx->>'descmt'" |
| 1113 | + " FROM reportfmt WHERE title GLOB %Q", |
| 1063 | 1114 | titleSearch); |
| 1064 | 1115 | rc = db_step(&q); |
| 1065 | 1116 | } |
| 1066 | 1117 | if( rc!=SQLITE_ROW ){ |
| 1067 | 1118 | db_finalize(&q); |
| | @@ -1073,10 +1124,12 @@ |
| 1073 | 1124 | zTitle = db_column_malloc(&q, 0); |
| 1074 | 1125 | zSql = db_column_malloc(&q, 1); |
| 1075 | 1126 | zOwner = db_column_malloc(&q, 2); |
| 1076 | 1127 | zClrKey = db_column_malloc(&q, 3); |
| 1077 | 1128 | rn = db_column_int(&q,4); |
| 1129 | + zDesc = db_column_malloc(&q, 5); |
| 1130 | + zMimetype = db_column_malloc(&q, 6); |
| 1078 | 1131 | db_finalize(&q); |
| 1079 | 1132 | |
| 1080 | 1133 | if( P("order_by") ){ |
| 1081 | 1134 | /* |
| 1082 | 1135 | ** If the user wants to do a column sort, wrap the query into a sub |
| | @@ -1117,10 +1170,17 @@ |
| 1117 | 1170 | } |
| 1118 | 1171 | if( g.perm.NewTkt ){ |
| 1119 | 1172 | style_submenu_element("New Ticket", "%R/tktnew"); |
| 1120 | 1173 | } |
| 1121 | 1174 | style_header("%s", zTitle); |
| 1175 | + } |
| 1176 | + if( zDesc && zMimetype ){ |
| 1177 | + Blob src; |
| 1178 | + blob_init(&src, zDesc, -1); |
| 1179 | + wiki_render_by_mimetype(&src, zMimetype); |
| 1180 | + blob_reset(&src); |
| 1181 | + @ <p> |
| 1122 | 1182 | } |
| 1123 | 1183 | output_color_key(zClrKey, 1, |
| 1124 | 1184 | "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\""); |
| 1125 | 1185 | @ <table border="1" cellpadding="2" cellspacing="0" class="report sortable" |
| 1126 | 1186 | @ data-column-types='' data-init-sort='0'> |
| 1127 | 1187 | |