freshbooks-cli 0.3.0 → 0.3.1
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/lib/fb/cli.rb +55 -4
- data/lib/fb/spinner.rb +20 -4
- data/lib/fb/version.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: 1a9fbab3436ac48b76db93a82b5b6ee909ab84e8928bb21ce0941c3547c1174e
|
|
4
|
+
data.tar.gz: 187a0da5b2fb4eb34f2df616573bc22fa819fa49da38a33b1df5bfab2fa5dba8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28163e4059f5d8b5ac7bb6aed4c49b7abdf1e3d3ebae078a4feccead18e6d6989bc5985b9794e9401570c99735bedadce33aa440696ca7e459cc5144a4d167ac
|
|
7
|
+
data.tar.gz: 5fc2c9c1b53be6557cd30edbfc9ce898f86fa9fbd5fdc19403ab379f5daf18e4e8ed1cb0ac9ffd3aa10bd11a9326ab01942707717cc619adf3d3b6f05b9505cb
|
data/lib/fb/cli.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "thor"
|
|
4
4
|
require "json"
|
|
5
5
|
require "date"
|
|
6
|
+
require "io/console"
|
|
6
7
|
|
|
7
8
|
module FB
|
|
8
9
|
class Cli < Thor
|
|
@@ -11,8 +12,16 @@ module FB
|
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
class_option :no_interactive, type: :boolean, default: false, desc: "Disable interactive prompts (auto-detected when not a TTY)"
|
|
15
|
+
class_option :interactive, type: :boolean, default: false, desc: "Force interactive mode even when not a TTY"
|
|
14
16
|
class_option :format, type: :string, desc: "Output format: table (default) or json"
|
|
15
17
|
|
|
18
|
+
no_commands do
|
|
19
|
+
def invoke_command(command, *args)
|
|
20
|
+
Spinner.interactive = interactive?
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
16
25
|
# --- version ---
|
|
17
26
|
|
|
18
27
|
desc "version", "Print the current version"
|
|
@@ -294,12 +303,12 @@ module FB
|
|
|
294
303
|
client = maps[:clients][e["client_id"].to_s] || e["client_id"].to_s
|
|
295
304
|
project = maps[:projects][e["project_id"].to_s] || "-"
|
|
296
305
|
service = maps[:services][e["service_id"].to_s] || "-"
|
|
297
|
-
note =
|
|
306
|
+
note = e["note"] || ""
|
|
298
307
|
hours = (e["duration"].to_i / 3600.0).round(2)
|
|
299
308
|
[e["id"].to_s, date, client, project, service, note, "#{hours}h"]
|
|
300
309
|
end
|
|
301
310
|
|
|
302
|
-
print_table(["ID", "Date", "Client", "Project", "Service", "Note", "Duration"], rows)
|
|
311
|
+
print_table(["ID", "Date", "Client", "Project", "Service", "Note", "Duration"], rows, wrap_col: 5)
|
|
303
312
|
|
|
304
313
|
total = entries.sum { |e| e["duration"].to_i } / 3600.0
|
|
305
314
|
puts "\nTotal: #{total.round(2)}h"
|
|
@@ -586,6 +595,7 @@ module FB
|
|
|
586
595
|
|
|
587
596
|
def interactive?
|
|
588
597
|
return false if options[:no_interactive]
|
|
598
|
+
return true if options[:interactive]
|
|
589
599
|
$stdin.tty?
|
|
590
600
|
end
|
|
591
601
|
|
|
@@ -747,15 +757,56 @@ module FB
|
|
|
747
757
|
input
|
|
748
758
|
end
|
|
749
759
|
|
|
750
|
-
def print_table(headers, rows)
|
|
760
|
+
def print_table(headers, rows, wrap_col: nil)
|
|
751
761
|
widths = headers.each_with_index.map do |h, i|
|
|
752
762
|
[h.length, *rows.map { |r| r[i].to_s.length }].max
|
|
753
763
|
end
|
|
754
764
|
|
|
765
|
+
# Word-wrap a specific column if it would exceed terminal width
|
|
766
|
+
if wrap_col
|
|
767
|
+
term_width = IO.console&.winsize&.last || ENV["COLUMNS"]&.to_i || 120
|
|
768
|
+
fixed_width = widths.each_with_index.sum { |w, i| i == wrap_col ? 0 : w } + (widths.length - 1) * 2
|
|
769
|
+
max_wrap = term_width - fixed_width
|
|
770
|
+
max_wrap = [max_wrap, 20].max
|
|
771
|
+
widths[wrap_col] = [widths[wrap_col], max_wrap].min
|
|
772
|
+
end
|
|
773
|
+
|
|
755
774
|
fmt = widths.map { |w| "%-#{w}s" }.join(" ")
|
|
756
775
|
puts fmt % headers
|
|
757
776
|
puts widths.map { |w| "-" * w }.join(" ")
|
|
758
|
-
|
|
777
|
+
|
|
778
|
+
rows.each do |r|
|
|
779
|
+
if wrap_col && r[wrap_col].to_s.length > widths[wrap_col]
|
|
780
|
+
lines = word_wrap(r[wrap_col].to_s, widths[wrap_col])
|
|
781
|
+
padded = widths.each_with_index.map { |w, i| i == wrap_col ? "" : " " * w }
|
|
782
|
+
pad_fmt = padded.each_with_index.map { |p, i| i == wrap_col ? "%s" : "%-#{widths[i]}s" }.join(" ")
|
|
783
|
+
lines.each_with_index do |line, li|
|
|
784
|
+
if li == 0
|
|
785
|
+
row = r.dup
|
|
786
|
+
row[wrap_col] = line
|
|
787
|
+
puts fmt % row
|
|
788
|
+
else
|
|
789
|
+
blank = padded.dup
|
|
790
|
+
blank[wrap_col] = line
|
|
791
|
+
puts pad_fmt % blank
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
else
|
|
795
|
+
puts fmt % r
|
|
796
|
+
end
|
|
797
|
+
end
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
def word_wrap(text, width)
|
|
801
|
+
lines = []
|
|
802
|
+
remaining = text
|
|
803
|
+
while remaining.length > width
|
|
804
|
+
break_at = remaining.rindex(" ", width) || width
|
|
805
|
+
lines << remaining[0...break_at]
|
|
806
|
+
remaining = remaining[break_at..].lstrip
|
|
807
|
+
end
|
|
808
|
+
lines << remaining unless remaining.empty?
|
|
809
|
+
lines
|
|
759
810
|
end
|
|
760
811
|
|
|
761
812
|
def print_status_section(title, entries, maps)
|
data/lib/fb/spinner.rb
CHANGED
|
@@ -4,15 +4,31 @@ module FB
|
|
|
4
4
|
module Spinner
|
|
5
5
|
FRAMES = %w[⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏].freeze
|
|
6
6
|
|
|
7
|
+
@interactive = nil
|
|
8
|
+
|
|
9
|
+
def self.interactive=(value)
|
|
10
|
+
@interactive = value
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.interactive?
|
|
14
|
+
return @interactive unless @interactive.nil?
|
|
15
|
+
$stderr.tty?
|
|
16
|
+
end
|
|
17
|
+
|
|
7
18
|
def self.spin(message)
|
|
8
|
-
done = false
|
|
9
19
|
result = nil
|
|
10
20
|
|
|
21
|
+
unless interactive?
|
|
22
|
+
result = yield
|
|
23
|
+
return result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
done = false
|
|
11
27
|
thread = Thread.new do
|
|
12
28
|
i = 0
|
|
13
29
|
while !done
|
|
14
|
-
print "\r#{FRAMES[i % FRAMES.length]} #{message}"
|
|
15
|
-
$
|
|
30
|
+
$stderr.print "\r#{FRAMES[i % FRAMES.length]} #{message}"
|
|
31
|
+
$stderr.flush
|
|
16
32
|
i += 1
|
|
17
33
|
sleep 0.08
|
|
18
34
|
end
|
|
@@ -23,7 +39,7 @@ module FB
|
|
|
23
39
|
ensure
|
|
24
40
|
done = true
|
|
25
41
|
thread.join
|
|
26
|
-
print "\r✓ #{message}\n"
|
|
42
|
+
$stderr.print "\r✓ #{message}\n"
|
|
27
43
|
end
|
|
28
44
|
|
|
29
45
|
result
|
data/lib/fb/version.rb
CHANGED