tng 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tng might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/Gemfile +15 -0
- data/LICENSE.md +32 -0
- data/README.md +427 -0
- data/Rakefile +124 -0
- data/bin/load_dev +22 -0
- data/bin/tng +1122 -0
- data/binaries/tng.bundle +0 -0
- data/binaries/tng.so +0 -0
- data/lib/generators/tng/install_generator.rb +236 -0
- data/lib/tng/analyzers/controller.rb +114 -0
- data/lib/tng/analyzers/model.rb +122 -0
- data/lib/tng/analyzers/service.rb +149 -0
- data/lib/tng/api/http_client.rb +102 -0
- data/lib/tng/railtie.rb +11 -0
- data/lib/tng/services/test_generator.rb +159 -0
- data/lib/tng/services/testng.rb +100 -0
- data/lib/tng/services/user_app_config.rb +77 -0
- data/lib/tng/ui/about_display.rb +64 -0
- data/lib/tng/ui/authentication_warning_display.rb +172 -0
- data/lib/tng/ui/configuration_display.rb +52 -0
- data/lib/tng/ui/controller_test_flow_display.rb +96 -0
- data/lib/tng/ui/display_banner.rb +44 -0
- data/lib/tng/ui/goodbye_display.rb +41 -0
- data/lib/tng/ui/model_test_flow_display.rb +97 -0
- data/lib/tng/ui/post_install_box.rb +82 -0
- data/lib/tng/ui/service_test_flow_display.rb +95 -0
- data/lib/tng/ui/show_help.rb +124 -0
- data/lib/tng/ui/system_status_display.rb +128 -0
- data/lib/tng/ui/theme.rb +248 -0
- data/lib/tng/ui/user_stats_display.rb +160 -0
- data/lib/tng/utils.rb +263 -0
- data/lib/tng/version.rb +5 -0
- data/lib/tng.rb +308 -0
- data/tng.gemspec +56 -0
- metadata +289 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pastel"
|
|
4
|
+
require_relative "theme"
|
|
5
|
+
|
|
6
|
+
class SystemStatusDisplay
|
|
7
|
+
def initialize(pastel, args)
|
|
8
|
+
@pastel = pastel
|
|
9
|
+
@args = args
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def display(status)
|
|
13
|
+
case status[:status]
|
|
14
|
+
when :ok
|
|
15
|
+
unless @args[:type] && @args[:file]
|
|
16
|
+
puts @pastel.public_send(Tng::UI::Theme.color(:success),
|
|
17
|
+
"#{Tng::UI::Theme.icon(:success)} System operational")
|
|
18
|
+
end
|
|
19
|
+
true
|
|
20
|
+
when :version_mismatch
|
|
21
|
+
display_status_message(
|
|
22
|
+
title: "Version Mismatch",
|
|
23
|
+
icon: Tng::UI::Theme.icon(:error),
|
|
24
|
+
color: Tng::UI::Theme.color(:error),
|
|
25
|
+
content: [
|
|
26
|
+
"Your gem version: #{status[:gem_version]}",
|
|
27
|
+
"Required version: #{status[:current_version]}",
|
|
28
|
+
"",
|
|
29
|
+
"Quick fix:",
|
|
30
|
+
"• gem update tng",
|
|
31
|
+
"• bundle update tng"
|
|
32
|
+
]
|
|
33
|
+
)
|
|
34
|
+
false
|
|
35
|
+
when :base_url_mismatch
|
|
36
|
+
display_status_message(
|
|
37
|
+
title: "URL Mismatch",
|
|
38
|
+
icon: Tng::UI::Theme.icon(:error),
|
|
39
|
+
color: Tng::UI::Theme.color(:error),
|
|
40
|
+
content: [
|
|
41
|
+
"Your URL: #{status[:user_base_url]}",
|
|
42
|
+
"Server URL: #{status[:server_base_url]}",
|
|
43
|
+
"",
|
|
44
|
+
"Quick fix:",
|
|
45
|
+
"• Edit config/initializers/tng.rb",
|
|
46
|
+
"• Set: config.base_url = '#{status[:server_base_url]}'"
|
|
47
|
+
]
|
|
48
|
+
)
|
|
49
|
+
false
|
|
50
|
+
when :service_down
|
|
51
|
+
display_status_message(
|
|
52
|
+
title: "Service Unavailable",
|
|
53
|
+
icon: Tng::UI::Theme.icon(:error),
|
|
54
|
+
color: Tng::UI::Theme.color(:error),
|
|
55
|
+
content: [
|
|
56
|
+
status[:message] || "TNG service is currently down",
|
|
57
|
+
"",
|
|
58
|
+
"Please try again later or contact support"
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
false
|
|
62
|
+
when :error
|
|
63
|
+
display_status_message(
|
|
64
|
+
title: "Connection Error",
|
|
65
|
+
icon: Tng::UI::Theme.icon(:error),
|
|
66
|
+
color: Tng::UI::Theme.color(:error),
|
|
67
|
+
content: [
|
|
68
|
+
status[:message] || "Unable to connect to TNG service",
|
|
69
|
+
"",
|
|
70
|
+
"Please check your internet connection and try again"
|
|
71
|
+
]
|
|
72
|
+
)
|
|
73
|
+
false
|
|
74
|
+
else
|
|
75
|
+
display_status_message(
|
|
76
|
+
title: "Unknown Error",
|
|
77
|
+
icon: Tng::UI::Theme.icon(:error),
|
|
78
|
+
color: Tng::UI::Theme.color(:error),
|
|
79
|
+
content: [status[:message] || "An unknown error occurred"]
|
|
80
|
+
)
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def display_status_message(title:, icon:, color:, content:)
|
|
88
|
+
require "tty-box"
|
|
89
|
+
require "tty-screen"
|
|
90
|
+
|
|
91
|
+
terminal_width = begin
|
|
92
|
+
TTY::Screen.width
|
|
93
|
+
rescue StandardError
|
|
94
|
+
80
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
formatted_content = content.map do |line|
|
|
98
|
+
case line
|
|
99
|
+
when /^•/
|
|
100
|
+
@pastel.public_send(Tng::UI::Theme.color(:muted), line)
|
|
101
|
+
when /^Quick fix:/
|
|
102
|
+
@pastel.public_send(Tng::UI::Theme.color(:secondary), line)
|
|
103
|
+
when ""
|
|
104
|
+
line
|
|
105
|
+
else
|
|
106
|
+
@pastel.public_send(Tng::UI::Theme.color(:warning), line)
|
|
107
|
+
end
|
|
108
|
+
end.join("\n")
|
|
109
|
+
|
|
110
|
+
box_width = Tng::UI::Theme.calculate_box_width(terminal_width)
|
|
111
|
+
|
|
112
|
+
status_box = TTY::Box.frame(
|
|
113
|
+
title: { top_left: " #{title} " },
|
|
114
|
+
style: {
|
|
115
|
+
fg: :bright_white,
|
|
116
|
+
border: { fg: color },
|
|
117
|
+
title: { fg: color == Tng::UI::Theme.color(:error) ? :bright_red : color }
|
|
118
|
+
},
|
|
119
|
+
padding: [1, 2],
|
|
120
|
+
width: box_width
|
|
121
|
+
) do
|
|
122
|
+
formatted_content
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
puts Tng::UI::Theme.center_box(status_box, box_width, terminal_width)
|
|
126
|
+
puts
|
|
127
|
+
end
|
|
128
|
+
end
|
data/lib/tng/ui/theme.rb
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tng
|
|
4
|
+
module UI
|
|
5
|
+
module Theme
|
|
6
|
+
# Icons - consistent across all UI components
|
|
7
|
+
ICONS = {
|
|
8
|
+
# Status icons
|
|
9
|
+
success: "✅",
|
|
10
|
+
error: "❌",
|
|
11
|
+
warning: "⚠️",
|
|
12
|
+
info: "ℹ️",
|
|
13
|
+
|
|
14
|
+
# Action icons
|
|
15
|
+
rocket: "🚀",
|
|
16
|
+
wave: "👋",
|
|
17
|
+
stats: "📊",
|
|
18
|
+
config: "📋",
|
|
19
|
+
heart: "❤️",
|
|
20
|
+
lightbulb: "💡",
|
|
21
|
+
|
|
22
|
+
# Navigation icons
|
|
23
|
+
back: "⬅️ ", # Added space after back arrow
|
|
24
|
+
marker: "▶",
|
|
25
|
+
bullet: "•"
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
# Colors - terminal-agnostic color scheme
|
|
29
|
+
COLORS = {
|
|
30
|
+
# Primary status colors
|
|
31
|
+
success: :green,
|
|
32
|
+
error: :red,
|
|
33
|
+
warning: :yellow,
|
|
34
|
+
info: :cyan,
|
|
35
|
+
|
|
36
|
+
# Text hierarchy colors
|
|
37
|
+
primary: :bright_white,
|
|
38
|
+
secondary: :cyan,
|
|
39
|
+
accent: :yellow,
|
|
40
|
+
muted: :dim,
|
|
41
|
+
|
|
42
|
+
# Border colors for boxes
|
|
43
|
+
border_success: :green,
|
|
44
|
+
border_error: :red,
|
|
45
|
+
border_warning: :yellow,
|
|
46
|
+
border_info: :cyan,
|
|
47
|
+
border_primary: :cyan
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
# Box styling constants
|
|
51
|
+
BOX_STYLES = {
|
|
52
|
+
default: {
|
|
53
|
+
style: {
|
|
54
|
+
border: {
|
|
55
|
+
type: :light,
|
|
56
|
+
top_left: "┌",
|
|
57
|
+
top_right: "┐",
|
|
58
|
+
bottom_left: "└",
|
|
59
|
+
bottom_right: "┘",
|
|
60
|
+
top: "─",
|
|
61
|
+
bottom: "─",
|
|
62
|
+
left: "│",
|
|
63
|
+
right: "│"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
padding: [1, 2],
|
|
67
|
+
max_width: 100
|
|
68
|
+
},
|
|
69
|
+
success: {
|
|
70
|
+
style: {
|
|
71
|
+
border: {
|
|
72
|
+
type: :light,
|
|
73
|
+
top_left: "┌",
|
|
74
|
+
top_right: "┐",
|
|
75
|
+
bottom_left: "└",
|
|
76
|
+
bottom_right: "┘",
|
|
77
|
+
top: "─",
|
|
78
|
+
bottom: "─",
|
|
79
|
+
left: "│",
|
|
80
|
+
right: "│"
|
|
81
|
+
},
|
|
82
|
+
fg: :green
|
|
83
|
+
},
|
|
84
|
+
padding: [1, 2],
|
|
85
|
+
max_width: 100
|
|
86
|
+
},
|
|
87
|
+
warning: {
|
|
88
|
+
style: {
|
|
89
|
+
border: {
|
|
90
|
+
type: :light,
|
|
91
|
+
top_left: "┌",
|
|
92
|
+
top_right: "┐",
|
|
93
|
+
bottom_left: "└",
|
|
94
|
+
bottom_right: "┘",
|
|
95
|
+
top: "─",
|
|
96
|
+
bottom: "─",
|
|
97
|
+
left: "│",
|
|
98
|
+
right: "│"
|
|
99
|
+
},
|
|
100
|
+
fg: :yellow
|
|
101
|
+
},
|
|
102
|
+
padding: [1, 2],
|
|
103
|
+
max_width: 100
|
|
104
|
+
}
|
|
105
|
+
}.freeze
|
|
106
|
+
|
|
107
|
+
# Helper methods for consistent styling
|
|
108
|
+
module_function
|
|
109
|
+
|
|
110
|
+
def detect_terminal_background
|
|
111
|
+
# Manual override for TNG (highest priority)
|
|
112
|
+
case ENV["TNG_TERMINAL_THEME"]&.downcase
|
|
113
|
+
when "light"
|
|
114
|
+
:light
|
|
115
|
+
when "dark"
|
|
116
|
+
:dark
|
|
117
|
+
else
|
|
118
|
+
get_background_color
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def get_background_color
|
|
123
|
+
print "\e]11;?\e\\"
|
|
124
|
+
$stdout.flush
|
|
125
|
+
|
|
126
|
+
require "timeout"
|
|
127
|
+
begin
|
|
128
|
+
response = ""
|
|
129
|
+
Timeout.timeout(0.1) do
|
|
130
|
+
response = $stdin.read_nonblock(100)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
case response
|
|
134
|
+
when %r{rgb:([0-9a-f]{4})/([0-9a-f]{4})/([0-9a-f]{4})}i
|
|
135
|
+
r, g, b = [::Regexp.last_match(1), ::Regexp.last_match(2), ::Regexp.last_match(3)].map do |hex|
|
|
136
|
+
hex.to_i(16) >> 8
|
|
137
|
+
end
|
|
138
|
+
brightness = (r * 0.299 + g * 0.587 + b * 0.114)
|
|
139
|
+
return brightness > 128 ? :light : :dark
|
|
140
|
+
when /rgb:([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i
|
|
141
|
+
r, g, b = [::Regexp.last_match(1), ::Regexp.last_match(2), ::Regexp.last_match(3)].map do |hex|
|
|
142
|
+
hex.to_i(16)
|
|
143
|
+
end
|
|
144
|
+
brightness = (r * 0.299 + g * 0.587 + b * 0.114)
|
|
145
|
+
return brightness > 128 ? :light : :dark
|
|
146
|
+
end
|
|
147
|
+
rescue IO::WaitReadable, Errno::EAGAIN
|
|
148
|
+
# No data available
|
|
149
|
+
rescue Timeout::Error, StandardError
|
|
150
|
+
# Fall back to environment detection
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Enhanced fallback detection
|
|
154
|
+
case ENV["TERM_PROGRAM"]
|
|
155
|
+
when "iTerm.app"
|
|
156
|
+
ENV["ITERM_PROFILE"]&.downcase&.include?("light") ? :light : :dark
|
|
157
|
+
when "Apple_Terminal"
|
|
158
|
+
:light # Terminal.app defaults to light
|
|
159
|
+
when "vscode"
|
|
160
|
+
:dark # VS Code integrated terminal usually dark
|
|
161
|
+
else
|
|
162
|
+
# Check for common dark theme indicators
|
|
163
|
+
if ENV["COLORTERM"] == "truecolor" || ENV["TERM"]&.include?("256")
|
|
164
|
+
:dark
|
|
165
|
+
else
|
|
166
|
+
:light
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def adaptive_color(color_key)
|
|
172
|
+
base_color = base_color(color_key)
|
|
173
|
+
|
|
174
|
+
# Adjust colors based on terminal background for optimal visibility
|
|
175
|
+
if detect_terminal_background == :light
|
|
176
|
+
# Light terminal adjustments
|
|
177
|
+
case base_color
|
|
178
|
+
when :dim
|
|
179
|
+
:black
|
|
180
|
+
when :bright_white
|
|
181
|
+
:black # White text invisible on light backgrounds
|
|
182
|
+
when :cyan
|
|
183
|
+
:blue # Cyan can be hard to read on light backgrounds
|
|
184
|
+
when :yellow
|
|
185
|
+
:red # Yellow invisible on light backgrounds
|
|
186
|
+
else
|
|
187
|
+
base_color
|
|
188
|
+
end
|
|
189
|
+
else
|
|
190
|
+
# Dark terminal adjustments - optimized for macOS Terminal
|
|
191
|
+
case base_color
|
|
192
|
+
when :dim
|
|
193
|
+
# macOS Terminal renders :white better than :bright_white
|
|
194
|
+
:white
|
|
195
|
+
when :black
|
|
196
|
+
:white # Black text invisible on dark backgrounds
|
|
197
|
+
when :cyan
|
|
198
|
+
# macOS Terminal cyan can be hard to read, use blue
|
|
199
|
+
:blue
|
|
200
|
+
when :yellow
|
|
201
|
+
# macOS Terminal yellow can be faded, use brighter alternatives
|
|
202
|
+
:red
|
|
203
|
+
when :bright_white
|
|
204
|
+
# Force to regular white for better macOS Terminal compatibility
|
|
205
|
+
:white
|
|
206
|
+
else
|
|
207
|
+
base_color
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def icon(name)
|
|
213
|
+
ICONS[name] || ""
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def color(name)
|
|
217
|
+
adaptive_color(name)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def base_color(name)
|
|
221
|
+
COLORS[name] || :white
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def box_style(name)
|
|
225
|
+
BOX_STYLES[name] || BOX_STYLES[:default]
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def calculate_box_width(terminal_width)
|
|
229
|
+
[terminal_width - 4, BOX_STYLES[:default][:max_width]].min
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def center_box(box_content, box_width, terminal_width)
|
|
233
|
+
lines = box_content.split("\n")
|
|
234
|
+
padding = (terminal_width - box_width) / 2
|
|
235
|
+
padding = 0 if padding.negative?
|
|
236
|
+
lines.map { |line| (" " * padding) + line }.join("\n")
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def center_text(text, terminal_width)
|
|
240
|
+
# Remove ANSI color codes for length calculation
|
|
241
|
+
clean_text = text.gsub(/\e\[[0-9;]*m/, "")
|
|
242
|
+
padding = (terminal_width - clean_text.length) / 2
|
|
243
|
+
padding = 0 if padding.negative?
|
|
244
|
+
(" " * padding) + text
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tty-box"
|
|
4
|
+
require "tty-progressbar"
|
|
5
|
+
require "pastel"
|
|
6
|
+
require "tty-screen"
|
|
7
|
+
require_relative "theme"
|
|
8
|
+
|
|
9
|
+
class UserStatsDisplay
|
|
10
|
+
def initialize(pastel, prompt)
|
|
11
|
+
@pastel = pastel
|
|
12
|
+
@prompt = prompt
|
|
13
|
+
@terminal_width = begin
|
|
14
|
+
TTY::Screen.width
|
|
15
|
+
rescue StandardError
|
|
16
|
+
80
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def display(stats_data)
|
|
21
|
+
header = @pastel.public_send(Tng::UI::Theme.color(:primary)).bold("#{Tng::UI::Theme.icon(:stats)} User Statistics")
|
|
22
|
+
puts Tng::UI::Theme.center_text(header, @terminal_width)
|
|
23
|
+
|
|
24
|
+
if stats_data
|
|
25
|
+
display_stats_box(stats_data)
|
|
26
|
+
display_usage_progress(stats_data)
|
|
27
|
+
display_usage_info(stats_data)
|
|
28
|
+
else
|
|
29
|
+
display_error
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
puts
|
|
33
|
+
tip_msg = @pastel.public_send(Tng::UI::Theme.color(:muted),
|
|
34
|
+
"#{Tng::UI::Theme.icon(:lightbulb)} Tip: Contact support if you need more test generations")
|
|
35
|
+
puts Tng::UI::Theme.center_text(tip_msg, @terminal_width)
|
|
36
|
+
@prompt.keypress(Tng::UI::Theme.center_text(
|
|
37
|
+
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
|
38
|
+
"Press any key to continue..."), @terminal_width
|
|
39
|
+
))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def display_stats_box(stats_data)
|
|
43
|
+
stats_content = [
|
|
44
|
+
@pastel.public_send(Tng::UI::Theme.color(:secondary)).bold("Account Information"),
|
|
45
|
+
"",
|
|
46
|
+
@pastel.public_send(Tng::UI::Theme.color(:primary), "Test Runs: ") + @pastel.public_send(Tng::UI::Theme.color(:success)).bold(stats_data["runs"].to_s),
|
|
47
|
+
@pastel.public_send(Tng::UI::Theme.color(:primary), "Max Runs: ") + @pastel.public_send(Tng::UI::Theme.color(:warning)).bold(stats_data["max_runs"].to_s),
|
|
48
|
+
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
|
49
|
+
"Gem Version: ") + @pastel.public_send(Tng::UI::Theme.color(:accent),
|
|
50
|
+
stats_data["gem_version"] || "N/A"),
|
|
51
|
+
"",
|
|
52
|
+
@pastel.public_send(Tng::UI::Theme.color(:muted), "Request ID: #{stats_data["request_id"]}")
|
|
53
|
+
].join("\n")
|
|
54
|
+
|
|
55
|
+
box_width = Tng::UI::Theme.calculate_box_width(@terminal_width)
|
|
56
|
+
style = Tng::UI::Theme.box_style(:success)
|
|
57
|
+
|
|
58
|
+
box = TTY::Box.frame(
|
|
59
|
+
title: { top_left: " Your TNG Stats " },
|
|
60
|
+
style: style[:style],
|
|
61
|
+
padding: style[:padding],
|
|
62
|
+
align: :left,
|
|
63
|
+
width: box_width
|
|
64
|
+
) { stats_content }
|
|
65
|
+
|
|
66
|
+
puts Tng::UI::Theme.center_box(box, box_width, @terminal_width)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def display_usage_progress(stats_data)
|
|
70
|
+
runs = stats_data["runs"]
|
|
71
|
+
max_runs = stats_data["max_runs"]
|
|
72
|
+
|
|
73
|
+
usage_percent = max_runs > 0 ? (runs.to_f / max_runs * 100).round(1) : 0
|
|
74
|
+
|
|
75
|
+
bar_color = determine_bar_color(usage_percent)
|
|
76
|
+
|
|
77
|
+
puts
|
|
78
|
+
puts Tng::UI::Theme.center_text(@pastel.public_send(Tng::UI::Theme.color(:primary)).bold("Usage Overview"),
|
|
79
|
+
@terminal_width)
|
|
80
|
+
puts
|
|
81
|
+
|
|
82
|
+
progress_width = 40
|
|
83
|
+
padding = (@terminal_width - progress_width - 20) / 2
|
|
84
|
+
padding = 0 if padding.negative?
|
|
85
|
+
|
|
86
|
+
bar_format = "#{" " * padding}Usage: [:bar] :percent (:current/:total)"
|
|
87
|
+
|
|
88
|
+
bar = TTY::ProgressBar.new(bar_format,
|
|
89
|
+
total: max_runs,
|
|
90
|
+
width: progress_width,
|
|
91
|
+
complete: bar_color,
|
|
92
|
+
incomplete: @pastel.public_send(Tng::UI::Theme.color(:muted), "░"),
|
|
93
|
+
head: bar_color)
|
|
94
|
+
|
|
95
|
+
current_progress = 0
|
|
96
|
+
while current_progress < runs
|
|
97
|
+
step = [runs / 10, 1].max
|
|
98
|
+
current_progress = [current_progress + step, runs].min
|
|
99
|
+
bar.current = current_progress
|
|
100
|
+
bar.render
|
|
101
|
+
sleep(0.05) if runs > 10
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
bar.current = runs
|
|
105
|
+
bar.render
|
|
106
|
+
|
|
107
|
+
puts
|
|
108
|
+
|
|
109
|
+
status_msg = case usage_percent
|
|
110
|
+
when 0..50
|
|
111
|
+
@pastel.public_send(Tng::UI::Theme.color(:success),
|
|
112
|
+
"#{Tng::UI::Theme.icon(:success)} Good usage - plenty of runs remaining")
|
|
113
|
+
when 51..80
|
|
114
|
+
@pastel.public_send(Tng::UI::Theme.color(:warning),
|
|
115
|
+
"#{Tng::UI::Theme.icon(:warning)} Moderate usage - consider monitoring")
|
|
116
|
+
when 81..95
|
|
117
|
+
@pastel.public_send(Tng::UI::Theme.color(:info),
|
|
118
|
+
"#{Tng::UI::Theme.icon(:warning)} High usage - approaching limit")
|
|
119
|
+
else
|
|
120
|
+
@pastel.public_send(Tng::UI::Theme.color(:error),
|
|
121
|
+
"#{Tng::UI::Theme.icon(:error)} Limit reached - contact support for more runs")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
puts Tng::UI::Theme.center_text(status_msg, @terminal_width)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def determine_bar_color(usage_percent)
|
|
128
|
+
case usage_percent
|
|
129
|
+
when 0..50
|
|
130
|
+
@pastel.public_send(Tng::UI::Theme.color(:success), "█")
|
|
131
|
+
when 51..80
|
|
132
|
+
@pastel.public_send(Tng::UI::Theme.color(:warning), "█")
|
|
133
|
+
when 81..95
|
|
134
|
+
@pastel.public_send(Tng::UI::Theme.color(:info), "█")
|
|
135
|
+
else
|
|
136
|
+
@pastel.public_send(Tng::UI::Theme.color(:error), "█")
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def display_usage_info(stats_data)
|
|
141
|
+
usage_remaining = stats_data["max_runs"] - stats_data["runs"]
|
|
142
|
+
usage_msg = if usage_remaining.positive?
|
|
143
|
+
@pastel.public_send(Tng::UI::Theme.color(:success),
|
|
144
|
+
"#{Tng::UI::Theme.icon(:success)} You have #{usage_remaining} test generations remaining")
|
|
145
|
+
else
|
|
146
|
+
@pastel.public_send(Tng::UI::Theme.color(:error),
|
|
147
|
+
"#{Tng::UI::Theme.icon(:warning)} You have reached your test generation limit")
|
|
148
|
+
end
|
|
149
|
+
puts Tng::UI::Theme.center_text(usage_msg, @terminal_width)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def display_error
|
|
153
|
+
error_msg = @pastel.public_send(Tng::UI::Theme.color(:error)).bold("#{Tng::UI::Theme.icon(:error)} Failed to fetch user statistics")
|
|
154
|
+
puts Tng::UI::Theme.center_text(error_msg, @terminal_width)
|
|
155
|
+
puts Tng::UI::Theme.center_text(
|
|
156
|
+
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
|
157
|
+
"Please check your API key and internet connection"), @terminal_width
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
end
|