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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/betters3tui.rb +86 -10
- data/lib/fuzzy.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 98a94ca0be3affeb0617f69182b5ec794b189ea5540b530346f2e5465db1b335
|
|
4
|
+
data.tar.gz: eec66f2677f6562e2e527c6b0a9da890524aef821db1d1e8319bb18c94477ad1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
-
|
|
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 @
|
|
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
|
-
|
|
1239
|
-
|
|
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 =
|
|
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|
|