tng 0.1.3 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93c59545652b35795ffe013a5dc4c9b27597653fec537c5c3ca01f6ffd9ded00
4
- data.tar.gz: 887ca462fafa51973c17d3b4d957f97ec74d13ecf634d7c7831c487c999122ba
3
+ metadata.gz: 58907277090e7b363bd0907be694ee5023ec4b18b0d24a4ab0956ba2e29fd648
4
+ data.tar.gz: 055abaa322144382a523118edbef976b6ded86425b18d5c6b0308c5e282d3d89
5
5
  SHA512:
6
- metadata.gz: f9ff073b8f7853794240cd4593bc9535a91641c11c3c657b9cb70813675364e2b12ccf9e4953458fd17889c3e8b61c9d21f97cc375737d55bca8dae6ea13f129
7
- data.tar.gz: 0e32a8ff528822270f7adbc96b393bb684c7a5973ca163dcfd3ba5452aa4ab061567d11f9a8707528b131942945029d80f282b36e9a045a6dad597a5ca71d447
6
+ metadata.gz: e321fee31b6b91e63c54a318b30f28b66cf05e4e342a2cca2fbc67d1fa76e86ee9102fd788ede777bd6d8f80f32bc7d46bfa985db7b82d4e1b91efe2e32addc3
7
+ data.tar.gz: eca7b0234cf41ef0466f4016229a9236c577e4b0488a227ffa96cfb2baac4587309e70dc95ef6460bad0b4225f98582f00e1c2a50c310e7259a39e3d97f0c3ea
data/README.md CHANGED
@@ -18,55 +18,6 @@ And then execute:
18
18
  bundle install
19
19
  ```
20
20
 
21
- ### Local Gem Installation
22
-
23
- If you have a local `.gem` file (e.g., for beta versions):
24
-
25
- #### Option 1: Direct Installation (Recommended)
26
-
27
- ```bash
28
- gem install ~/Downloads/tng-0.1.0.gem
29
- ```
30
-
31
- Then add to your `Gemfile`:
32
- ```ruby
33
- gem "tng", "~> 0.1.0"
34
- ```
35
-
36
- Run bundle install:
37
- ```bash
38
- bundle install
39
- ```
40
-
41
- #### Option 2: Vendor Path Installation
42
-
43
- 1. Create vendor directory structure:
44
- ```bash
45
- mkdir -p vendor/gems
46
- ```
47
-
48
- 2. Unpack the gem:
49
- ```bash
50
- cd vendor/gems
51
- rm -rf tng-0.1.0 # Remove existing folder if it exists
52
- gem unpack ~/Downloads/tng-0.1.0.gem
53
- cd ../..
54
- ```
55
-
56
- 3. Add to your `Gemfile`:
57
- ```ruby
58
- gem "tng", path: "vendor/gems/tng-0.1.0"
59
- ```
60
-
61
- 4. Run bundle install:
62
- ```bash
63
- bundle install
64
- ```
65
-
66
- ### Installation Troubleshooting
67
-
68
- For detailed installation troubleshooting, see the [Troubleshooting](#troubleshooting) section.
69
-
70
21
  ## Configuration
71
22
 
72
23
  TNG requires proper configuration to generate high-quality tests. Generate the configuration file by running:
@@ -397,36 +348,6 @@ bundle exec tng -h # Short help
397
348
 
398
349
  ## Troubleshooting
399
350
 
400
- ### Installation Issues
401
-
402
- #### Gem Installation Problems
403
-
404
- **Error: "Could not find gem 'tng'"**
405
- - Ensure you installed the gem file first: `gem install ~/Downloads/tng-0.1.0.gem`
406
- - Check installed gems: `gem list tng`
407
- - Verify gem name and version in Gemfile matches installed gem
408
-
409
- **Error: "No such file ~/Downloads/tng-0.1.0.gem"**
410
- - Verify correct path to downloaded gem file
411
- - Use `ls ~/Downloads/tng*` to check exact filename
412
-
413
- **Error: "Could not find gem 'tng' in source" (vendor path)**
414
- - Verify path points to correct unpacked directory
415
- - Ensure `vendor/gems/tng-0.1.0/` contains `.gemspec` file
416
- - Check gem was unpacked correctly: `gem unpack ~/Downloads/tng-0.1.0.gem`
417
-
418
- #### Binary Loading Problems
419
-
420
- **Error: "Native extension not found"**
421
- - Check your platform is supported (macOS or Linux x86_64)
422
- - Verify binary exists: `ls vendor/gems/tng-*/lib/tng/`
423
- - Try reinstalling: `bundle install --force`
424
-
425
- **Error: "Symbol not found" or "Library not loaded"**
426
- - macOS: Ensure you have Xcode command line tools: `xcode-select --install`
427
- - Linux: Ensure glibc compatibility
428
- - Try clearing gem cache: `gem cleanup tng`
429
-
430
351
  ### Configuration Issues
431
352
 
432
353
  #### API Key Problems
data/bin/tng CHANGED
@@ -23,6 +23,7 @@ require "tng/ui/show_help"
23
23
  require "tng/ui/post_install_box"
24
24
  require "tng/ui/system_status_display"
25
25
  require "tng/ui/configuration_display"
26
+ require "tng/ui/authentication_warning_display"
26
27
  require "tng/ui/display_banner"
27
28
  require "tng/ui/user_stats_display"
28
29
  require "tng/ui/about_display"
@@ -503,6 +504,9 @@ class CLI
503
504
 
504
505
  return if test_option == :back
505
506
 
507
+ # Check authentication configuration before proceeding with test generation
508
+ return unless check_authentication_configuration
509
+
506
510
  case test_option
507
511
  when :all_possible_tests
508
512
  generate_test_for_controller(controller_choice)
@@ -517,6 +521,9 @@ class CLI
517
521
 
518
522
  return if test_option == :back
519
523
 
524
+ # Check authentication configuration before proceeding with test generation
525
+ return unless check_authentication_configuration
526
+
520
527
  case test_option
521
528
  when :all_possible_tests
522
529
  generate_test_for_model(model_choice)
@@ -531,6 +538,9 @@ class CLI
531
538
 
532
539
  return if test_option == :back
533
540
 
541
+ # Check authentication configuration before proceeding with test generation
542
+ return unless check_authentication_configuration
543
+
534
544
  case test_option
535
545
  when :all_possible_tests
536
546
  generate_test_for_service(service_choice)
@@ -853,6 +863,19 @@ class CLI
853
863
  false
854
864
  end
855
865
 
866
+ def check_authentication_configuration
867
+ auth_warning = AuthenticationWarningDisplay.new(@pastel)
868
+ auth_missing = auth_warning.display_if_missing
869
+
870
+ if auth_missing
871
+ # User chose to cancel (pressed Esc)
872
+ return false
873
+ end
874
+
875
+ # User chose to continue (pressed Enter) or no auth issues
876
+ true
877
+ end
878
+
856
879
  # ABOUT
857
880
  def show_about
858
881
  AboutDisplay.new(@pastel, @prompt, Tng::VERSION).display
@@ -877,6 +900,9 @@ class CLI
877
900
  # Check configuration first
878
901
  return unless check_configuration
879
902
 
903
+ # Check authentication configuration
904
+ return unless check_authentication_configuration
905
+
880
906
  # Check system status (but don't show the spinner in direct mode)
881
907
  status = @testng.check_system_status
882
908
  unless SystemStatusDisplay.new(@pastel, params).display(status)
@@ -68,6 +68,7 @@ module Tng
68
68
  "",
69
69
  "Tng.configure do |config|",
70
70
  " config.api_key = nil",
71
+ " # You dont need to change this url, unless you will instructed by the CLI.",
71
72
  " config.base_url = \"https://app.tng.sh/\"",
72
73
  " config.read_source_code = true # Options: true, false",
73
74
  " config.read_test_code = true # Options: true, false",
@@ -83,21 +84,28 @@ module Tng
83
84
  " #{auth_enabled} # Options: true, false",
84
85
  " #{auth_lib} # Options: devise, clearance, sorcery, nil",
85
86
  "",
87
+ "",
88
+ " # ⚠️ IMPORTANT: AUTHENTICATION CONFIGURATION REQUIRED ⚠️",
89
+ " # You MUST configure your authentication methods below for TNG to work properly.",
90
+ " # Uncomment and modify the authentication_methods configuration:",
91
+ "",
86
92
  " # Authentication Methods (multiple methods supported)",
87
93
  " # Supported authentication types: session, devise, jwt, token_auth, basic_auth, oauth, headers, custom, nil",
88
- " # Uncomment and configure your authentication entry points:",
94
+ " # EXAMPLE: Uncomment and modify these examples to match your app's authentication:",
95
+ "",
89
96
  " # config.authentication_methods = [",
90
- " # {",
91
- " # method: \"authenticate_user_via_session!\",",
92
- " # file_location: \"app/controllers/application_controller.rb\",",
93
- " # auth_type: \"session\"",
94
- " # },",
95
- " # {",
96
- " # method: \"authenticate_user_via_api_key!\",",
97
- " # file_location: \"app/controllers/application_controller.rb\",",
98
- " # auth_type: \"headers\"",
99
- " # }",
97
+ " # {",
98
+ " # method: \"authenticate_user_via_session!\",",
99
+ " # file_location: \"app/controllers/application_controller.rb\",",
100
+ " # auth_type: \"session\"",
101
+ " # },",
102
+ " # {",
103
+ " # method: \"authenticate_user_via_api_key!\",",
104
+ " # file_location: \"app/controllers/application_controller.rb\",",
105
+ " # auth_type: \"headers\"",
106
+ " # }",
100
107
  " # ]",
108
+ " # ⚠️ Remember to configure your authentication methods above! ⚠️",
101
109
  "",
102
110
  " # Authorization#{authz_comment}",
103
111
  " #{authz_lib} # Options: cancancan, pundit, rolify, nil",
@@ -209,12 +217,12 @@ module Tng
209
217
 
210
218
  def generate_framework_specific_config(framework, framework_config)
211
219
  if framework == "minitest"
212
- " config.test_style = \"#{framework_config["test_style"]}\" # Options: spec, unit, test_block\n" +
220
+ " config.test_style = \"#{framework_config["test_style"]}\" # Options: spec, unit, test_block\n" +
213
221
  " config.setup_style = #{framework_config["setup_style"]} # Options: true, false\n" +
214
222
  " config.assertion_style = \"#{framework_config["assertion_style"]}\" # Options: assert/refute, assert/assert_not, must/wont\n" +
215
223
  " config.teardown_style = #{framework_config["teardown_style"]} # Options: true, false"
216
224
  else # rspec
217
- " config.describe_style = #{framework_config["describe_style"]} # Options: true, false\n" +
225
+ " config.describe_style = #{framework_config["describe_style"]} # Options: true, false\n" +
218
226
  " config.context_style = \"#{framework_config["context_style"]}\" # Options: context, describe\n" +
219
227
  " config.it_style = \"#{framework_config["it_style"]}\" # Options: it, specify\n" +
220
228
  " config.before_style = \"#{framework_config["before_style"]}\" # Options: before, setup\n" +
@@ -25,7 +25,7 @@ module Services
25
25
  server_base_url = data["base_url"]
26
26
  user_base_url = Tng::Services::UserAppConfig.base_url
27
27
 
28
- if current_version != Tng::VERSION
28
+ if current_version > Tng::VERSION
29
29
  return {
30
30
  status: :version_mismatch,
31
31
  message: "Version mismatch detected",
@@ -3,6 +3,7 @@
3
3
  require "tty-box"
4
4
  require "pastel"
5
5
  require "tty-screen"
6
+ require_relative "theme"
6
7
 
7
8
  class AboutDisplay
8
9
  def initialize(pastel, prompt, version)
@@ -10,62 +11,54 @@ class AboutDisplay
10
11
  @prompt = prompt
11
12
  @version = version
12
13
  @terminal_width = begin
13
- TTY::Screen.width
14
- rescue StandardError
15
- 80
16
- end
14
+ TTY::Screen.width
15
+ rescue StandardError
16
+ 80
17
+ end
17
18
  end
18
19
 
19
20
  def display
20
21
  about_content = [
21
- @pastel.cyan.bold("About Tng"),
22
+ @pastel.public_send(Tng::UI::Theme.color(:secondary)).bold("About Tng"),
22
23
  "",
23
- @pastel.bright_white("Tng is an LLM-powered test generation tool for Rails applications."),
24
+ @pastel.public_send(Tng::UI::Theme.color(:primary),
25
+ "Tng is an LLM-powered test generation tool for Rails applications."),
24
26
  "",
25
- @pastel.bold("Features:"),
26
- " Controller test generation",
27
- " Model test generation",
28
- " LLM-powered test suggestions",
29
- " Test coverage analysis",
27
+ @pastel.public_send(Tng::UI::Theme.color(:accent), "Features:"),
28
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "#{Tng::UI::Theme.icon(:bullet)} Controller test generation"),
29
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "#{Tng::UI::Theme.icon(:bullet)} Model test generation"),
30
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "#{Tng::UI::Theme.icon(:bullet)} Service test generation"),
31
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "#{Tng::UI::Theme.icon(:bullet)} LLM-powered test suggestions"),
32
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "#{Tng::UI::Theme.icon(:bullet)} Test coverage analysis"),
30
33
  "",
31
- @pastel.bold("Technology:"),
32
- "• Static code analysis with Prism",
33
- " Intelligent pattern recognition",
34
- "• Rails-specific optimizations",
34
+ @pastel.public_send(Tng::UI::Theme.color(:accent), "Technology:"),
35
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
36
+ "#{Tng::UI::Theme.icon(:bullet)} Static code analysis with Prism"),
37
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
38
+ "#{Tng::UI::Theme.icon(:bullet)} Intelligent pattern recognition"),
39
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "#{Tng::UI::Theme.icon(:bullet)} Rails-specific optimizations"),
35
40
  "",
36
- @pastel.dim("Version: #{@version}"),
37
- @pastel.dim("Built with ❤️ for Rails developers")
41
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "Version: #{@version}"),
42
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
43
+ "Built with #{Tng::UI::Theme.icon(:heart)} for Rails developers")
38
44
  ].join("\n")
39
45
 
40
- box_width = 64
46
+ box_width = Tng::UI::Theme.calculate_box_width(@terminal_width)
47
+ style = Tng::UI::Theme.box_style(:default)
48
+
41
49
  about_box = TTY::Box.frame(
42
50
  title: { top_left: " About Tng " },
43
- style: {
44
- fg: :bright_white,
45
- border: { fg: :cyan },
46
- title: { fg: :bright_cyan }
47
- },
48
- padding: [1, 2],
51
+ style: style[:style],
52
+ padding: style[:padding],
49
53
  width: box_width
50
54
  ) do
51
55
  about_content
52
56
  end
53
57
 
54
- puts center_box(about_box, box_width)
55
- @prompt.keypress(center_text(@pastel.dim("Press any key to continue...")))
56
- end
57
-
58
- private
59
-
60
- def center_text(text)
61
- padding = (@terminal_width - @pastel.strip(text).length) / 2
62
- padding = 0 if padding.negative?
63
- (" " * padding) + text
64
- end
65
-
66
- def center_box(box_string, box_width)
67
- padding = (@terminal_width - box_width) / 2
68
- padding = 0 if padding.negative?
69
- box_string.lines.map { |line| (" " * padding) + line.chomp }.join("\n")
58
+ puts Tng::UI::Theme.center_box(about_box, box_width, @terminal_width)
59
+ @prompt.keypress(Tng::UI::Theme.center_text(
60
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
61
+ "Press any key to continue..."), @terminal_width
62
+ ))
70
63
  end
71
64
  end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tty-box"
4
+ require "pastel"
5
+ require "tty-screen"
6
+ require_relative "theme"
7
+
8
+ class AuthenticationWarningDisplay
9
+ def initialize(pastel)
10
+ @pastel = pastel
11
+ @terminal_width = begin
12
+ TTY::Screen.width
13
+ rescue StandardError
14
+ 80
15
+ end
16
+ end
17
+
18
+ def display_if_missing
19
+ return false unless authentication_config_missing?
20
+
21
+ display_warning
22
+ handle_user_choice
23
+ end
24
+
25
+ def display_warning
26
+ warning_content = [
27
+ @pastel.public_send(Tng::UI::Theme.color(:error)).bold("Authentication Configuration Missing"),
28
+ "",
29
+ @pastel.public_send(Tng::UI::Theme.color(:primary), "TNG needs authentication setup to generate proper tests."),
30
+ "",
31
+ @pastel.public_send(Tng::UI::Theme.color(:accent), "Missing: ") + build_missing_items_summary,
32
+ "",
33
+ @pastel.public_send(Tng::UI::Theme.color(:secondary), "Quick fix:"),
34
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
35
+ "#{Tng::UI::Theme.icon(:bullet)} Edit config/initializers/tng.rb"),
36
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
37
+ "#{Tng::UI::Theme.icon(:bullet)} Uncomment authentication_methods array"),
38
+ @pastel.public_send(Tng::UI::Theme.color(:muted), "#{Tng::UI::Theme.icon(:bullet)} Add your auth method details"),
39
+ "",
40
+ @pastel.public_send(Tng::UI::Theme.color(:success), "Press Enter to continue anyway"),
41
+ @pastel.public_send(Tng::UI::Theme.color(:error), "Press Esc to cancel and fix configuration")
42
+ ].join("\n")
43
+
44
+ box_width = Tng::UI::Theme.calculate_box_width(@terminal_width)
45
+ style = Tng::UI::Theme.box_style(:warning)
46
+
47
+ warning_box = TTY::Box.frame(
48
+ title: { top_left: " Auth Warning " },
49
+ style: style[:style],
50
+ padding: style[:padding],
51
+ width: box_width
52
+ ) do
53
+ warning_content
54
+ end
55
+
56
+ puts Tng::UI::Theme.center_box(warning_box, box_width, @terminal_width)
57
+ puts
58
+ end
59
+
60
+ private
61
+
62
+ def handle_user_choice
63
+ require "io/console"
64
+
65
+ loop do
66
+ key = $stdin.getch
67
+ case key
68
+ when "\r", "\n" # Enter key
69
+ return false # Continue anyway
70
+ when "\e" # Escape key
71
+ return true # Cancel (authentication missing)
72
+ when "\u0003" # Ctrl+C
73
+ puts "\n#{@pastel.public_send(Tng::UI::Theme.color(:warning), "Operation cancelled.")}"
74
+ exit(0)
75
+ end
76
+ end
77
+ rescue StandardError
78
+ # Fallback if getch is not available
79
+ puts @pastel.public_send(Tng::UI::Theme.color(:muted), "Press Enter to continue or Ctrl+C to cancel...")
80
+ gets
81
+ false
82
+ end
83
+
84
+ def build_missing_items_summary
85
+ issues = []
86
+
87
+ issues << "empty auth methods" if Tng.authentication_enabled && authentication_methods_empty?
88
+
89
+ issues << "invalid auth config" if !authentication_methods_empty? && !authentication_methods_valid?
90
+
91
+ issues << "auth disabled" unless Tng.authentication_enabled
92
+
93
+ issues.empty? ? "unknown issue" : issues.join(", ")
94
+ end
95
+
96
+ def authentication_config_missing?
97
+ # Check if authentication is enabled but methods are not configured
98
+ return true if Tng.authentication_enabled && authentication_methods_empty?
99
+
100
+ # Check if authentication methods exist but are invalid
101
+ return true if !authentication_methods_empty? && !authentication_methods_valid?
102
+
103
+ false
104
+ end
105
+
106
+ def authentication_methods_empty?
107
+ methods = Tng.authentication_methods
108
+ methods.nil? || methods.empty?
109
+ end
110
+
111
+ def authentication_methods_valid?
112
+ methods = Tng.authentication_methods
113
+ return false if methods.nil? || methods.empty?
114
+
115
+ methods.all? do |method|
116
+ method.is_a?(Hash) &&
117
+ method.key?(:method) && !method[:method].to_s.strip.empty? &&
118
+ method.key?(:file_location) && !method[:file_location].to_s.strip.empty? &&
119
+ method.key?(:auth_type) && !method[:auth_type].to_s.strip.empty?
120
+ end
121
+ end
122
+
123
+ def build_missing_items_list
124
+ issues = []
125
+
126
+ if Tng.authentication_enabled && authentication_methods_empty?
127
+ issues << @pastel.public_send(Tng::UI::Theme.color(:error), " • authentication_methods array is empty")
128
+ end
129
+
130
+ if !authentication_methods_empty? && !authentication_methods_valid?
131
+ issues << @pastel.public_send(Tng::UI::Theme.color(:error), " • authentication_methods contains invalid entries")
132
+
133
+ Tng.authentication_methods.each_with_index do |method, index|
134
+ next if method.is_a?(Hash)
135
+
136
+ issues << @pastel.public_send(Tng::UI::Theme.color(:muted), " - Entry #{index + 1}: not a valid hash")
137
+ next
138
+ end
139
+
140
+ Tng.authentication_methods.each_with_index do |method, index|
141
+ next unless method.is_a?(Hash)
142
+
143
+ if !method.key?(:method) || method[:method].to_s.strip.empty?
144
+ issues << @pastel.public_send(Tng::UI::Theme.color(:muted),
145
+ " - Entry #{index + 1}: missing or empty 'method'")
146
+ end
147
+
148
+ if !method.key?(:file_location) || method[:file_location].to_s.strip.empty?
149
+ issues << @pastel.public_send(Tng::UI::Theme.color(:muted),
150
+ " - Entry #{index + 1}: missing or empty 'file_location'")
151
+ end
152
+
153
+ if !method.key?(:auth_type) || method[:auth_type].to_s.strip.empty?
154
+ issues << @pastel.public_send(Tng::UI::Theme.color(:muted),
155
+ " - Entry #{index + 1}: missing or empty 'auth_type'")
156
+ end
157
+ end
158
+ end
159
+
160
+ unless Tng.authentication_enabled
161
+ issues << @pastel.public_send(Tng::UI::Theme.color(:warning),
162
+ " • authentication_enabled is set to false")
163
+ end
164
+
165
+ if issues.empty?
166
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
167
+ " • Configuration appears valid")
168
+ else
169
+ issues.join("\n")
170
+ end
171
+ end
172
+ end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "tty-box"
3
4
  require "pastel"
4
5
  require "tty-screen"
6
+ require_relative "theme"
5
7
 
6
8
  class ConfigurationDisplay
7
9
  def initialize(pastel)
@@ -14,33 +16,37 @@ class ConfigurationDisplay
14
16
  end
15
17
 
16
18
  def display_missing_config(missing_config)
17
- puts @pastel.red.bold("❌ Configuration Required!")
18
- puts
19
- puts @pastel.yellow("Missing required configuration:")
20
- missing_config.each do |key|
21
- puts @pastel.cyan(" • #{key}")
22
- end
23
- puts
24
- puts @pastel.bright_white("Please edit your configuration file:")
25
- puts @pastel.cyan(" config/initializers/tng.rb")
26
- puts
27
- puts @pastel.bright_white("Ensure these values are set:")
28
- puts @pastel.cyan(" Tng.configure do |config|")
29
- puts @pastel.cyan(" config.api_key = \"your-api-key-here\"") if missing_config.include?("api_key")
30
- puts @pastel.cyan(" config.testing_framework = \"minitest\"") if missing_config.include?("test_framework")
31
- puts @pastel.cyan(" end")
32
- puts
33
- puts @pastel.dim("💡 Run 'rails generate tng:install' to create a proper config file.")
34
- puts @pastel.dim("💡 Verify the generated setup corresponds to your project settings.")
35
- puts
36
- puts @pastel.yellow("After configuring, run 'bundle exec tng' again.")
37
- end
19
+ config_content = [
20
+ @pastel.public_send(Tng::UI::Theme.color(:error)).bold("Configuration Required"),
21
+ "",
22
+ @pastel.public_send(Tng::UI::Theme.color(:accent), "Missing required configuration:"),
23
+ missing_config.map do |key|
24
+ @pastel.public_send(Tng::UI::Theme.color(:secondary), "#{Tng::UI::Theme.icon(:bullet)} #{key}")
25
+ end.join("\n"),
26
+ "",
27
+ @pastel.public_send(Tng::UI::Theme.color(:secondary), "Quick fix:"),
28
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
29
+ "#{Tng::UI::Theme.icon(:bullet)} Edit config/initializers/tng.rb"),
30
+ @pastel.public_send(Tng::UI::Theme.color(:muted),
31
+ "#{Tng::UI::Theme.icon(:bullet)} Set your API key and other required values"),
32
+ "",
33
+ @pastel.public_send(Tng::UI::Theme.color(:success), "Press Enter to continue after fixing"),
34
+ @pastel.public_send(Tng::UI::Theme.color(:error), "Press Ctrl+C to exit")
35
+ ].join("\n")
38
36
 
39
- private
37
+ box_width = Tng::UI::Theme.calculate_box_width(@terminal_width)
38
+ style = Tng::UI::Theme.box_style(:error)
40
39
 
41
- def center_text(text)
42
- padding = (@terminal_width - @pastel.strip(text).length) / 2
43
- padding = 0 if padding.negative?
44
- (" " * padding) + text
40
+ config_box = TTY::Box.frame(
41
+ title: { top_left: " Config Required " },
42
+ style: style[:style],
43
+ padding: style[:padding],
44
+ width: box_width
45
+ ) do
46
+ config_content
47
+ end
48
+
49
+ puts Tng::UI::Theme.center_box(config_box, box_width, @terminal_width)
50
+ puts
45
51
  end
46
52
  end