betters3tui 0.2.5 → 0.2.7

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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/lib/betters3tui.rb +86 -10
  4. data/lib/fuzzy.rb +1 -1
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a38bace5feab978c53307d83130bb1846a52c9b024b1588cb87105ed1f3528e6
4
- data.tar.gz: e85a7aab711a451329a9c6f8f7605b0d61a29bafdaab2c730f993580b1501dcb
3
+ metadata.gz: 98a94ca0be3affeb0617f69182b5ec794b189ea5540b530346f2e5465db1b335
4
+ data.tar.gz: eec66f2677f6562e2e527c6b0a9da890524aef821db1d1e8319bb18c94477ad1
5
5
  SHA512:
6
- metadata.gz: b547d135fa3ee99704d329013bacb11106b1c01162e984072c97923016ebf238a01c3b669fa2d79562f22b18d22c74f0e68020d640315435ffb2dc1c5b7dc9bc
7
- data.tar.gz: '0950b85f3a174d694b9291790ccf2ce570326eae8faf0ed7d8e951d0efdc4edbfedfaeff651932a725ed2ad19e4ef1d820371b1a4f3c085513093f8190c2948d'
6
+ metadata.gz: 35cfff2e92a797dae2c56441f30908dca5d01a7979508f327776a050428ce26a6fed12e793a33f523943edfa1fe47995d327e461bf6254942fe2e62e3a94d9d8
7
+ data.tar.gz: b0341c937891c6c662508750aee3b1f12b7094d2b1c6ca1fdee6de786603b869f734d81606448842118fd20dcfb522f7279bc81b5584d7f72f12057aa8ec9ac2
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.2.7] - 2026-02-28
6
+
7
+ ### Fixed
8
+ - **Auto-create profiles.json** - App now automatically creates the config directory and empty profiles.json file on first run instead of exiting with an error
9
+
10
+ ## [0.2.6] - 2026-02-27
11
+
12
+ ### Added
13
+ - **Download progress bar** - Visual progress indicator when downloading files with percentage, file size, and completion status
14
+ - **Loading indicators** - Show "Loading buckets..." and "Loading directory contents..." when fetching data from S3
15
+
16
+ ### Fixed
17
+ - **Ruby compatibility** - Fixed `Data.define` error for Ruby versions < 3.2 by using `Struct` instead
18
+
5
19
  ## [0.1.1] - 2026-02-27
6
20
 
7
21
  ### Added
@@ -25,5 +39,7 @@ All notable changes to this project will be documented in this file.
25
39
  - File download capability
26
40
  - Interactive keyboard navigation
27
41
 
42
+ [0.2.7]: https://github.com/adiprnm/betters3tui/compare/v0.2.6...v0.2.7
43
+ [0.2.6]: https://github.com/adiprnm/betters3tui/compare/v0.2.5...v0.2.6
28
44
  [0.1.1]: https://github.com/adiprnm/betters3tui/compare/v0.1.0...v0.1.1
29
45
  [0.1.0]: https://github.com/adiprnm/betters3tui/releases/tag/v0.1.0
data/lib/betters3tui.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- VERSION = "0.2.5"
4
+ VERSION = "0.2.7"
5
5
 
6
6
  require "json"
7
7
  require "aws-sdk-s3"
@@ -62,15 +62,14 @@ class S3Browser
62
62
  { key: 'd', label: 'Date', value: :date }
63
63
  ]
64
64
  @sort_menu_index = 0
65
+
66
+ # Loading state
67
+ @loading = false
68
+ @loading_message = ""
65
69
  end
66
70
 
67
71
  def run
68
- if @profiles.empty?
69
- puts "No profiles found at #{PROFILES_PATH}"
70
- puts "Please create a profiles.json file with your S3 credentials."
71
- exit 1
72
- end
73
-
72
+ ensure_profiles_file_exists
74
73
  setup_terminal
75
74
 
76
75
  loop do
@@ -93,6 +92,16 @@ class S3Browser
93
92
  []
94
93
  end
95
94
 
95
+ def ensure_profiles_file_exists
96
+ require 'fileutils'
97
+ config_dir = File.dirname(PROFILES_PATH)
98
+ FileUtils.mkdir_p(config_dir) unless File.exist?(config_dir)
99
+
100
+ unless File.exist?(PROFILES_PATH)
101
+ File.write(PROFILES_PATH, JSON.pretty_generate([]))
102
+ end
103
+ end
104
+
96
105
  def setup_terminal
97
106
  @original_stty = `stty -g 2>/dev/null`.chomp
98
107
  system("stty -echo -icanon raw 2>/dev/null")
@@ -172,7 +181,23 @@ class S3Browser
172
181
  line.right.write_dim(node_count_text)
173
182
  end
174
183
 
175
- if @message && Time.now - @message_time < 3
184
+ if @loading
185
+ screen.footer.add_line do |line|
186
+ line.write << Tui::Text.highlight(@loading_message)
187
+ end
188
+ elsif @downloading && @download_progress
189
+ progress = @download_progress
190
+ percent = (progress[:downloaded].to_f / progress[:total] * 100).round(1)
191
+ bar_width = 20
192
+ filled = (percent / 100 * bar_width).to_i
193
+ bar = "█" * filled + "░" * (bar_width - filled)
194
+ downloaded_str = format_size(progress[:downloaded])
195
+ total_str = format_size(progress[:total])
196
+ progress_msg = "Downloading #{progress[:filename]}: [#{bar}] #{percent}% (#{downloaded_str}/#{total_str})"
197
+ screen.footer.add_line do |line|
198
+ line.write << Tui::Text.highlight(progress_msg)
199
+ end
200
+ elsif @message && Time.now - @message_time < 3
176
201
  screen.footer.add_line do |line|
177
202
  line.write << (@message.include?("Error") ? Tui::Text.accent(@message) : Tui::Text.highlight(@message))
178
203
  end
@@ -1164,16 +1189,27 @@ class S3Browser
1164
1189
  def list_buckets
1165
1190
  return unless @s3_client
1166
1191
 
1192
+ @loading = true
1193
+ @loading_message = "Loading buckets..."
1194
+ render
1195
+
1167
1196
  response = @s3_client.list_buckets
1168
1197
  @buckets = response.buckets
1169
1198
  rescue => e
1170
1199
  show_message("Error listing buckets: #{e.message}")
1171
1200
  @buckets = []
1201
+ ensure
1202
+ @loading = false
1172
1203
  end
1173
1204
 
1174
1205
  def list_objects
1175
1206
  return unless @s3_client && @current_bucket
1176
1207
 
1208
+ # Show loading indicator
1209
+ @loading = true
1210
+ @loading_message = "Loading directory contents..."
1211
+ render
1212
+
1177
1213
  delimiter = "/"
1178
1214
  response = @s3_client.list_objects_v2(
1179
1215
  bucket: @current_bucket,
@@ -1203,6 +1239,8 @@ class S3Browser
1203
1239
  rescue => e
1204
1240
  show_message("Error listing objects: #{e.message}")
1205
1241
  @objects = []
1242
+ ensure
1243
+ @loading = false
1206
1244
  end
1207
1245
 
1208
1246
  def download_current
@@ -1234,18 +1272,56 @@ class S3Browser
1234
1272
  counter += 1
1235
1273
  end
1236
1274
 
1275
+ @downloading = true
1237
1276
  begin
1238
- @s3_client.get_object(
1239
- response_target: download_path,
1277
+ # Get file size first
1278
+ head_response = @s3_client.head_object(
1240
1279
  bucket: @current_bucket,
1241
1280
  key: key
1242
1281
  )
1282
+ total_size = head_response.content_length
1283
+
1284
+ # Download with progress
1285
+ downloaded = 0
1286
+ File.open(download_path, 'wb') do |file|
1287
+ @s3_client.get_object(
1288
+ bucket: @current_bucket,
1289
+ key: key
1290
+ ) do |chunk|
1291
+ file.write(chunk)
1292
+ downloaded += chunk.bytesize
1293
+ @download_progress = {
1294
+ filename: filename,
1295
+ downloaded: downloaded,
1296
+ total: total_size
1297
+ }
1298
+ render
1299
+ end
1300
+ end
1243
1301
  show_message("Downloaded: #{filename}")
1244
1302
  rescue => e
1245
1303
  show_message("Error downloading: #{e.message}")
1304
+ ensure
1305
+ @downloading = false
1306
+ @download_progress = nil
1246
1307
  end
1247
1308
  end
1248
1309
 
1310
+ def show_download_progress(filename, downloaded, total)
1311
+ return if total.nil? || total == 0
1312
+
1313
+ percent = (downloaded.to_f / total * 100).round(1)
1314
+ bar_width = 20
1315
+ filled = (percent / 100 * bar_width).to_i
1316
+ bar = "█" * filled + "░" * (bar_width - filled)
1317
+
1318
+ downloaded_str = format_size(downloaded)
1319
+ total_str = format_size(total)
1320
+
1321
+ @message = "Downloading #{filename}: [#{bar}] #{percent}% (#{downloaded_str}/#{total_str})"
1322
+ @message_time = Time.now
1323
+ end
1324
+
1249
1325
  def show_message(msg)
1250
1326
  @message = msg
1251
1327
  @message_time = Time.now
data/lib/fuzzy.rb CHANGED
@@ -20,7 +20,7 @@
20
20
  # fuzzy.match("proj").limit(10).each { |entry, positions, score| ... }
21
21
  #
22
22
  class Fuzzy
23
- Entry = Data.define(:data, :text, :text_lower, :base_score)
23
+ Entry = Struct.new(:data, :text, :text_lower, :base_score, keyword_init: true)
24
24
 
25
25
  def initialize(entries)
26
26
  @entries = entries.map do |e|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: betters3tui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adi Purnama