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
{