diff --git a/cli/src/commands/wheels/assets/init.cfc b/cli/src/commands/wheels/assets/init.cfc index a453f61b8..ae334f6ce 100644 --- a/cli/src/commands/wheels/assets/init.cfc +++ b/cli/src/commands/wheels/assets/init.cfc @@ -247,7 +247,7 @@ component extends="../base" { if (len(content) && right(content, 1) != chr(10)) { content &= chr(10); } - content &= chr(10) & "# Vite build output" & chr(10); + content = content & chr(10) & "## Vite build output" & chr(10); content &= arguments.entry & chr(10); fileWrite(gitignorePath, content); detailOutput.update(".gitignore", true); diff --git a/cli/src/commands/wheels/jobs/monitor.cfc b/cli/src/commands/wheels/jobs/monitor.cfc index 41822554e..c76d22223 100644 --- a/cli/src/commands/wheels/jobs/monitor.cfc +++ b/cli/src/commands/wheels/jobs/monitor.cfc @@ -8,7 +8,9 @@ * wheels jobs monitor --queue=mailers * {code} */ -component extends="../../base" { +component extends="../base" { + + property name="detailOutput" inject="DetailOutputService@wheels-cli"; /** * @interval Refresh interval in seconds (default: 3) @@ -25,10 +27,9 @@ component extends="../../base" { return; } - print.line(); - print.boldMagentaLine("Wheels Job Monitor"); - print.line("Press Ctrl+C to stop"); - print.line(); + detailOutput.header("Wheels Job Monitor"); + detailOutput.output("Press Ctrl+C to stop"); + detailOutput.line(); while (true) { // Build URL parameters @@ -42,77 +43,54 @@ component extends="../../base" { if (StructKeyExists(local.result, "success") && local.result.success) { // Clear previous output with separator - print.line(RepeatString("=", 60)); - print.boldCyanLine("Job Queue Dashboard - #TimeFormat(Now(), "HH:mm:ss")#"); - print.line(RepeatString("-", 60)); + detailOutput.divider("=", 60); + detailOutput.getPrint().boldCyanLine("Job Queue Dashboard - #TimeFormat(Now(), "HH:mm:ss")#"); + detailOutput.divider("-", 60); // Queue statistics if (StructKeyExists(local.result, "stats") && StructKeyExists(local.result.stats, "totals")) { local.t = local.result.stats.totals; - print.line(); - print.boldLine("Queue Summary:"); - print.yellowLine(" Pending: #local.t.pending#"); - print.cyanLine(" Processing: #local.t.processing#"); - print.greenLine(" Completed: #local.t.completed#"); - if (local.t.failed > 0) { - print.redLine(" Failed: #local.t.failed#"); - } else { - print.line(" Failed: #local.t.failed#"); - } - print.line(" Total: #local.t.total#"); + detailOutput.subHeader("Queue Summary"); + detailOutput.metric("Pending", local.t.pending); + detailOutput.metric("Processing", local.t.processing); + detailOutput.metric("Completed", local.t.completed); + detailOutput.metric("Failed", local.t.failed); + detailOutput.metric("Total", local.t.total); } // Throughput if (StructKeyExists(local.result, "monitor")) { local.m = local.result.monitor; - print.line(); - print.boldLine("Throughput (last 60 min):"); - print.greenLine(" Completed: #local.m.throughput.completed#"); - if (local.m.throughput.failed > 0) { - print.redLine(" Failed: #local.m.throughput.failed#"); - } else { - print.line(" Failed: #local.m.throughput.failed#"); - } - if (local.m.errorRate > 0) { - print.redLine(" Error rate: #local.m.errorRate#%"); - } else { - print.greenLine(" Error rate: 0%"); - } + detailOutput.subHeader("Throughput (last 60 min)"); + detailOutput.metric("Completed", local.m.throughput.completed); + detailOutput.metric("Failed", local.m.throughput.failed); + detailOutput.metric("Error rate", "#local.m.errorRate#%"); if (Len(local.m.oldestPending)) { - print.line(); - print.line("Oldest pending job: #DateTimeFormat(local.m.oldestPending, 'yyyy-mm-dd HH:mm:ss')#"); + detailOutput.line(); + detailOutput.output("Oldest pending job: #DateTimeFormat(local.m.oldestPending, 'yyyy-mm-dd HH:mm:ss')#"); } // Recent jobs if (ArrayLen(local.m.recentJobs)) { - print.line(); - print.boldLine("Recent Jobs:"); + detailOutput.subHeader("Recent Jobs"); local.count = Min(ArrayLen(local.m.recentJobs), 5); for (local.i = 1; local.i <= local.count; local.i++) { local.job = local.m.recentJobs[local.i]; - local.statusColor = "line"; - if (local.job.status == "completed") local.statusColor = "greenLine"; - else if (local.job.status == "failed") local.statusColor = "redLine"; - else if (local.job.status == "processing") local.statusColor = "cyanLine"; - else if (local.job.status == "pending") local.statusColor = "yellowLine"; - - print["#local.statusColor#"]( - " [#local.job.status#] #local.job.jobClass# (#local.job.queue#) - #DateTimeFormat(local.job.updatedAt, 'HH:mm:ss')#" - ); + detailOutput.output(" [#local.job.status#] #local.job.jobClass# (#local.job.queue#) - #DateTimeFormat(local.job.updatedAt, 'HH:mm:ss')#"); } } } // Timeout recoveries if (StructKeyExists(local.result, "timeoutsRecovered") && local.result.timeoutsRecovered > 0) { - print.line(); - print.yellowLine("Recovered #local.result.timeoutsRecovered# timed-out job(s)"); + detailOutput.line(); + detailOutput.statusWarning("Recovered #local.result.timeoutsRecovered# timed-out job(s)"); } } } catch (any e) { - print.redLine("[#TimeFormat(Now(), "HH:mm:ss")#] Monitor error: #e.message#"); + detailOutput.error("[#TimeFormat(Now(), "HH:mm:ss")#] Monitor error: #e.message#"); } sleep(arguments.interval * 1000); diff --git a/cli/src/commands/wheels/jobs/purge.cfc b/cli/src/commands/wheels/jobs/purge.cfc index 1456f89e3..70619e2cb 100644 --- a/cli/src/commands/wheels/jobs/purge.cfc +++ b/cli/src/commands/wheels/jobs/purge.cfc @@ -8,7 +8,9 @@ * wheels jobs purge --completed --failed --force * {code} */ -component extends="../../base" { +component extends="../base" { + + property name="detailOutput" inject="DetailOutputService@wheels-cli"; /** * @completed Purge completed jobs (default: true) @@ -31,9 +33,7 @@ component extends="../../base" { return; } - print.line(); - print.boldBlueLine("Purge Jobs"); - print.line(); + detailOutput.header("Purge Jobs"); local.totalPurged = 0; @@ -48,9 +48,9 @@ component extends="../../base" { if (StructKeyExists(local.result, "success") && local.result.success && StructKeyExists(local.result, "purged")) { local.totalPurged += local.result.purged; if (local.result.purged > 0) { - print.greenLine("Purged #local.result.purged# completed job(s) older than #arguments.olderThan# day(s)."); + detailOutput.success("Purged #local.result.purged# completed job(s) older than #arguments.olderThan# day(s)."); } else { - print.line("No completed jobs to purge."); + detailOutput.output("No completed jobs to purge."); } } } @@ -66,19 +66,16 @@ component extends="../../base" { if (StructKeyExists(local.result, "success") && local.result.success && StructKeyExists(local.result, "purged")) { local.totalPurged += local.result.purged; if (local.result.purged > 0) { - print.greenLine("Purged #local.result.purged# failed job(s) older than #arguments.olderThan# day(s)."); + detailOutput.success("Purged #local.result.purged# failed job(s) older than #arguments.olderThan# day(s)."); } else { - print.line("No failed jobs to purge."); + detailOutput.output("No failed jobs to purge."); } } } if (local.totalPurged > 0) { - print.line(); - print.boldGreenLine("Total purged: #local.totalPurged# job(s)"); + detailOutput.success("Total purged: #local.totalPurged# job(s)"); } - - print.line(); } } diff --git a/cli/src/commands/wheels/jobs/retry.cfc b/cli/src/commands/wheels/jobs/retry.cfc index f50ff26ed..2adda14cc 100644 --- a/cli/src/commands/wheels/jobs/retry.cfc +++ b/cli/src/commands/wheels/jobs/retry.cfc @@ -7,7 +7,9 @@ * wheels jobs retry --limit=10 * {code} */ -component extends="../../base" { +component extends="../base" { + + property name="detailOutput" inject="DetailOutputService@wheels-cli"; /** * @queue Filter by queue name (default: all queues) @@ -24,9 +26,7 @@ component extends="../../base" { return; } - print.line(); - print.boldBlueLine("Retry Failed Jobs"); - print.line(); + detailOutput.header("Retry Failed Jobs"); // Build URL parameters local.urlParams = "&command=jobsRetry"; @@ -44,14 +44,12 @@ component extends="../../base" { if (StructKeyExists(local.result, "retried")) { if (local.result.retried > 0) { - print.greenLine("Retried #local.result.retried# failed job(s)."); - print.line("Jobs have been reset to 'pending' and will be processed on the next cycle."); + detailOutput.success("Retried #local.result.retried# failed job(s)."); + detailOutput.output("Jobs have been reset to 'pending' and will be processed on the next cycle."); } else { - print.line("No failed jobs to retry."); + detailOutput.output("No failed jobs to retry."); } } - - print.line(); } } diff --git a/cli/src/commands/wheels/jobs/status.cfc b/cli/src/commands/wheels/jobs/status.cfc index 57a5ad928..0d6c202c7 100644 --- a/cli/src/commands/wheels/jobs/status.cfc +++ b/cli/src/commands/wheels/jobs/status.cfc @@ -7,7 +7,9 @@ * wheels jobs status --format=json * {code} */ -component extends="../../base" { +component extends="../base" { + + property name="detailOutput" inject="DetailOutputService@wheels-cli"; /** * @queue Filter by queue name (default: all queues) @@ -24,9 +26,7 @@ component extends="../../base" { return; } - print.line(); - print.boldBlueLine("Job Queue Status"); - print.line(); + detailOutput.header("Job Queue Status"); // Build URL parameters local.urlParams = "&command=jobsStatus"; @@ -40,7 +40,7 @@ component extends="../../base" { } if (arguments.format == "json") { - print.line(SerializeJSON(local.result.stats)); + detailOutput.output(SerializeJSON(local.result.stats)); return; } @@ -49,8 +49,8 @@ component extends="../../base" { local.queues = local.result.stats.queues; if (StructCount(local.queues) == 0) { - print.line("No jobs found."); - print.line(); + detailOutput.output("No jobs found."); + detailOutput.line(); return; } @@ -63,47 +63,47 @@ component extends="../../base" { PadRight("Total", 10) & " |"; local.separator = RepeatString("-", Len(local.header)); - print.line(local.separator); - print.line(local.header); - print.line(local.separator); + detailOutput.getPrint().line(local.separator); + detailOutput.getPrint().line(local.header); + detailOutput.getPrint().line(local.separator); for (local.queueName in local.queues) { local.q = local.queues[local.queueName]; - print.text("| " & PadRight(local.queueName, 20) & " | "); - print.yellowText(PadRight(local.q.pending, 10)); - print.text(" | "); - print.cyanText(PadRight(local.q.processing, 12)); - print.text(" | "); - print.greenText(PadRight(local.q.completed, 12)); - print.text(" | "); + detailOutput.getPrint().text("| " & PadRight(local.queueName, 20) & " | "); + detailOutput.getPrint().yellowText(PadRight(local.q.pending, 10)); + detailOutput.getPrint().text(" | "); + detailOutput.getPrint().cyanText(PadRight(local.q.processing, 12)); + detailOutput.getPrint().text(" | "); + detailOutput.getPrint().greenText(PadRight(local.q.completed, 12)); + detailOutput.getPrint().text(" | "); if (local.q.failed > 0) { - print.redText(PadRight(local.q.failed, 10)); + detailOutput.getPrint().redText(PadRight(local.q.failed, 10)); } else { - print.text(PadRight(local.q.failed, 10)); + detailOutput.getPrint().text(PadRight(local.q.failed, 10)); } - print.line(" | " & PadRight(local.q.total, 10) & " |"); + detailOutput.getPrint().line(" | " & PadRight(local.q.total, 10) & " |"); } // Totals row local.totals = local.result.stats.totals; - print.line(local.separator); - print.text("| " & PadRight("TOTAL", 20) & " | "); - print.boldYellowText(PadRight(local.totals.pending, 10)); - print.text(" | "); - print.boldCyanText(PadRight(local.totals.processing, 12)); - print.text(" | "); - print.boldGreenText(PadRight(local.totals.completed, 12)); - print.text(" | "); + detailOutput.getPrint().line(local.separator); + detailOutput.getPrint().text("| " & PadRight("TOTAL", 20) & " | "); + detailOutput.getPrint().boldYellowText(PadRight(local.totals.pending, 10)); + detailOutput.getPrint().text(" | "); + detailOutput.getPrint().boldCyanText(PadRight(local.totals.processing, 12)); + detailOutput.getPrint().text(" | "); + detailOutput.getPrint().boldGreenText(PadRight(local.totals.completed, 12)); + detailOutput.getPrint().text(" | "); if (local.totals.failed > 0) { - print.boldRedText(PadRight(local.totals.failed, 10)); + detailOutput.getPrint().boldRedText(PadRight(local.totals.failed, 10)); } else { - print.boldText(PadRight(local.totals.failed, 10)); + detailOutput.getPrint().boldText(PadRight(local.totals.failed, 10)); } - print.line(" | " & PadRight(local.totals.total, 10) & " |"); - print.line(local.separator); + detailOutput.getPrint().line(" | " & PadRight(local.totals.total, 10) & " |"); + detailOutput.getPrint().line(local.separator); } - print.line(); + detailOutput.line(); } private string function PadRight(required string text, required numeric length) { diff --git a/cli/src/commands/wheels/jobs/work.cfc b/cli/src/commands/wheels/jobs/work.cfc index d6ad43485..9f8fbefd4 100644 --- a/cli/src/commands/wheels/jobs/work.cfc +++ b/cli/src/commands/wheels/jobs/work.cfc @@ -11,7 +11,9 @@ * wheels jobs work --max-jobs=100 * {code} */ -component extends="../../base" { +component extends="../base" { + + property name="detailOutput" inject="DetailOutputService@wheels-cli"; /** * @queue Comma-delimited queue names to process (default: all queues) @@ -34,21 +36,20 @@ component extends="../../base" { return; } - print.line(); - print.boldCyanLine("Wheels Job Worker"); - print.line("Press Ctrl+C to stop"); - print.line(); + detailOutput.header("Wheels Job Worker"); + detailOutput.output("Press Ctrl+C to stop"); + detailOutput.line(); if (Len(arguments.queue)) { - print.greenLine("Queues: #arguments.queue#"); + detailOutput.metric("Queues", arguments.queue); } else { - print.greenLine("Queues: all"); + detailOutput.metric("Queues", "all"); } - print.greenLine("Poll interval: #arguments.interval#s"); + detailOutput.metric("Poll interval", "#arguments.interval#s"); if (arguments.maxJobs > 0) { - print.greenLine("Max jobs: #arguments.maxJobs#"); + detailOutput.metric("Max jobs", arguments.maxJobs); } - print.line(); + detailOutput.line(); local.processed = 0; local.failed = 0; @@ -75,14 +76,14 @@ component extends="../../base" { } else if (StructKeyExists(local.jr, "success") && local.jr.success) { local.processed++; if (!arguments.quiet) { - print.greenLine("[#TimeFormat(Now(), "HH:mm:ss")#] Completed: #local.jr.jobClass# (#local.jr.jobId#)"); + detailOutput.output("[#TimeFormat(Now(), "HH:mm:ss")#] Completed: #local.jr.jobClass# (#local.jr.jobId#)"); } // Check max jobs limit if (arguments.maxJobs > 0 && local.processed >= arguments.maxJobs) { - print.line(); - print.boldGreenLine("Reached max jobs limit (#arguments.maxJobs#). Shutting down."); - print.line("Processed: #local.processed# | Failed: #local.failed#"); + detailOutput.line(); + detailOutput.success("Reached max jobs limit (#arguments.maxJobs#). Shutting down."); + detailOutput.output("Processed: #local.processed# | Failed: #local.failed#"); return; } @@ -91,19 +92,19 @@ component extends="../../base" { } else { local.failed++; local.errorMsg = StructKeyExists(local.jr, "error") ? local.jr.error : "Unknown error"; - print.redLine("[#TimeFormat(Now(), "HH:mm:ss")#] Failed: #local.jr.jobClass# - #local.errorMsg#"); + detailOutput.error("[#TimeFormat(Now(), "HH:mm:ss")#] Failed: #local.jr.jobClass# - #local.errorMsg#"); // Check max jobs limit (failures count too) if (arguments.maxJobs > 0 && (local.processed + local.failed) >= arguments.maxJobs) { - print.line(); - print.boldGreenLine("Reached max jobs limit (#arguments.maxJobs#). Shutting down."); - print.line("Processed: #local.processed# | Failed: #local.failed#"); + detailOutput.line(); + detailOutput.success("Reached max jobs limit (#arguments.maxJobs#). Shutting down."); + detailOutput.output("Processed: #local.processed# | Failed: #local.failed#"); return; } } } } catch (any e) { - print.redLine("[#TimeFormat(Now(), "HH:mm:ss")#] Worker error: #e.message#"); + detailOutput.error("[#TimeFormat(Now(), "HH:mm:ss")#] Worker error: #e.message#"); } sleep(arguments.interval * 1000); diff --git a/cli/src/models/AdminViewService.cfc b/cli/src/models/AdminViewService.cfc index 8175e4085..40e0972b0 100644 --- a/cli/src/models/AdminViewService.cfc +++ b/cli/src/models/AdminViewService.cfc @@ -179,9 +179,9 @@ component { // Boolean — Yes/No badges if (field.dataType == "boolean" || field.inputType == "checkbox") { - return "Yes' - & 'No'; + & chr(60) & 'cfelse>No' & chr(60) & '/cfif>'; } // Email — mailto link diff --git a/cli/src/models/TestMigrationService.cfc b/cli/src/models/TestMigrationService.cfc index e3caa18b5..37ef54cb4 100644 --- a/cli/src/models/TestMigrationService.cfc +++ b/cli/src/models/TestMigrationService.cfc @@ -553,8 +553,8 @@ component singleton { }, // Structure key exists { - pattern = 'assert\s*\(\s*"structKeyExists\s*\(\s*([^,]+),\s*["\']([^"\']+)["\']\s*\)"\s*\)', - replace = 'expect($1).toHaveKey("$2")' + pattern = "assert\s*\(\s*""structKeyExists\s*\(\s*([^,]+),\s*[']([^']+)[']\s*\)""\s*\)", + replace = "expect($1).toHaveKey(""$2"")" }, // Length checks {