flycal-cli 0.2.1 → 0.3.0
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/README.md +2 -0
- data/lib/flycal_cli/cli.rb +108 -23
- data/lib/flycal_cli/version.rb +1 -1
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c6e56787081596ebef227a579b0667514fa493998875f613167acdade53a4899
|
|
4
|
+
data.tar.gz: a8776aded68f58ba58759adc27b3aeb2ca63eacf9797eb8bc161aeb2f96589ee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e0af4be4d8505aa21a63e4e6ed70f886419eddf971745154174ea55ec6348030cc0fdad3e40af926df128fa295a5741da84fe236930b2ec797259c2ba300219
|
|
7
|
+
data.tar.gz: d2021d42bc26dd9b82c4b7b672c923b137b2e83e1f983af96310b9c9d14e948c33cce752f99ba1f99e175d9071067484d2eb5b0763b5d8d63bf1ccb0d56085f4
|
data/README.md
CHANGED
|
@@ -101,6 +101,8 @@ The summary shows:
|
|
|
101
101
|
- Number of events found
|
|
102
102
|
- Total time occupied (hours, minutes, and working days based on 8-hour days)
|
|
103
103
|
|
|
104
|
+
For time frames longer than 7 days, a weekly breakdown is added (week number, start/end dates, hours, working days per week). For time frames longer than 30 days, a monthly breakdown is shown instead (month number, month name, hours, working days per month).
|
|
105
|
+
|
|
104
106
|
## Configuration
|
|
105
107
|
|
|
106
108
|
Data is stored in `~/.flycal/`:
|
data/lib/flycal_cli/cli.rb
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
require "thor"
|
|
4
4
|
require "time"
|
|
5
5
|
require "date"
|
|
6
|
+
require "active_support/core_ext/date"
|
|
7
|
+
require "active_support/core_ext/integer"
|
|
8
|
+
require "active_support/core_ext/time"
|
|
6
9
|
require "tty-prompt"
|
|
7
10
|
require "tty-spinner"
|
|
8
11
|
|
|
@@ -130,10 +133,10 @@ module FlycalCli
|
|
|
130
133
|
time_min = options[:from].to_s.empty? ? Date.today.to_time : parse_datetime(options[:from])
|
|
131
134
|
begin
|
|
132
135
|
time_max = if options[:in].to_s.empty?
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
options[:to].to_s.empty? ? (Date.today + 30).to_time + 86400 - 1 : parse_datetime(options[:to], end_of_day: true)
|
|
137
|
+
else
|
|
138
|
+
parse_duration_in(options[:in], time_min)
|
|
139
|
+
end
|
|
137
140
|
rescue FlycalCli::Error => e
|
|
138
141
|
puts "Error: #{e.message}"
|
|
139
142
|
exit 1
|
|
@@ -161,13 +164,19 @@ module FlycalCli
|
|
|
161
164
|
)
|
|
162
165
|
|
|
163
166
|
print_events(service, events)
|
|
164
|
-
|
|
167
|
+
print_search_summary(events, time_min: time_min, time_max: time_max)
|
|
165
168
|
end
|
|
166
169
|
|
|
167
170
|
default_task :help
|
|
168
171
|
|
|
169
172
|
private
|
|
170
173
|
|
|
174
|
+
HOURS_PER_WORKING_DAY = 8
|
|
175
|
+
|
|
176
|
+
def bold(str)
|
|
177
|
+
"\e[1m#{str}\e[0m"
|
|
178
|
+
end
|
|
179
|
+
|
|
171
180
|
def parse_datetime(str, end_of_day: false)
|
|
172
181
|
return nil if str.nil? || str.empty?
|
|
173
182
|
|
|
@@ -255,36 +264,112 @@ module FlycalCli
|
|
|
255
264
|
if dt.is_a?(String)
|
|
256
265
|
dt
|
|
257
266
|
else
|
|
258
|
-
dt.strftime("%Y-%m-%d %H:%M")
|
|
267
|
+
dt.strftime("%a %Y-%m-%d %H:%M")
|
|
259
268
|
end
|
|
260
269
|
end
|
|
261
270
|
|
|
262
|
-
def
|
|
263
|
-
|
|
271
|
+
def format_date_with_day(dt)
|
|
272
|
+
return "-" if dt.nil?
|
|
264
273
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
end_dt = event.end&.date_time || event.end&.date
|
|
274
|
+
t = dt.respond_to?(:to_time) ? dt.to_time : dt
|
|
275
|
+
t.strftime("%a %Y-%m-%d")
|
|
276
|
+
end
|
|
269
277
|
|
|
270
|
-
|
|
278
|
+
def print_search_summary(events, time_min:, time_max:)
|
|
279
|
+
event_ranges = extract_event_ranges(events)
|
|
280
|
+
total_minutes = event_ranges.sum { |s, e| (e - s) / 60 }
|
|
271
281
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
282
|
+
from_str = time_min.strftime("%a %Y-%m-%d %H:%M")
|
|
283
|
+
to_str = time_max.strftime("%a %Y-%m-%d %H:%M")
|
|
284
|
+
|
|
285
|
+
puts "\n---"
|
|
286
|
+
puts "From: #{from_str} | To: #{to_str}"
|
|
287
|
+
puts "Events found: #{events.size}"
|
|
288
|
+
puts "Total time occupied: #{format_duration(total_minutes)}"
|
|
289
|
+
|
|
290
|
+
frame_days = (time_max - time_min) / 86400.0
|
|
291
|
+
if frame_days > 30
|
|
292
|
+
print_monthly_breakdown(event_ranges, time_min, time_max)
|
|
293
|
+
elsif frame_days > 7
|
|
294
|
+
print_weekly_breakdown(event_ranges, time_min, time_max)
|
|
275
295
|
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def extract_event_ranges(events)
|
|
299
|
+
events.filter_map do |item|
|
|
300
|
+
event = item[:event]
|
|
301
|
+
start_t = event.start&.date_time || event.start&.date
|
|
302
|
+
end_t = event.end&.date_time || event.end&.date
|
|
303
|
+
next if start_t.nil? || end_t.nil?
|
|
276
304
|
|
|
305
|
+
start_t = start_t.to_time if start_t.respond_to?(:to_time)
|
|
306
|
+
end_t = end_t.to_time if end_t.respond_to?(:to_time)
|
|
307
|
+
[start_t, end_t]
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def format_duration(total_minutes)
|
|
277
312
|
hours = (total_minutes / 60).floor
|
|
278
313
|
mins = (total_minutes % 60).round
|
|
279
|
-
|
|
314
|
+
working_days = (total_minutes / 60.0 / HOURS_PER_WORKING_DAY).round(1)
|
|
315
|
+
"#{bold(hours)}h #{bold(mins)}min (#{bold(working_days)} working days)"
|
|
316
|
+
end
|
|
280
317
|
|
|
281
|
-
|
|
282
|
-
|
|
318
|
+
def format_hours_and_days(hours, working_days)
|
|
319
|
+
"#{bold(hours)}h (#{bold(working_days)} working days)"
|
|
320
|
+
end
|
|
283
321
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
322
|
+
def minutes_in_period(event_ranges, period_start, period_end)
|
|
323
|
+
event_ranges.sum do |ev_start, ev_end|
|
|
324
|
+
overlap_start = [ev_start, period_start].max
|
|
325
|
+
overlap_end = [ev_end, period_end].min
|
|
326
|
+
overlap_sec = overlap_end - overlap_start
|
|
327
|
+
overlap_sec > 0 ? overlap_sec / 60.0 : 0
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def print_weekly_breakdown(event_ranges, time_min, time_max)
|
|
332
|
+
puts "\nBy week:"
|
|
333
|
+
week_num = 1
|
|
334
|
+
current = time_min.to_date.beginning_of_week(:monday)
|
|
335
|
+
while current.to_time < time_max
|
|
336
|
+
week_start = [current.to_time, time_min].max
|
|
337
|
+
week_end_date = current.end_of_week(:monday)
|
|
338
|
+
week_end = [week_end_date.to_time + 1.day, time_max].min
|
|
339
|
+
mins = minutes_in_period(event_ranges, week_start, week_end)
|
|
340
|
+
hours = (mins / 60).round(1)
|
|
341
|
+
working_days = (mins / 60.0 / HOURS_PER_WORKING_DAY).round(1)
|
|
342
|
+
start_str = format_date_with_day(week_start)
|
|
343
|
+
end_str = format_date_with_day(week_end_date)
|
|
344
|
+
puts " #{bold(week_num)}. #{start_str} - #{end_str}: #{format_hours_and_days(hours, working_days)}"
|
|
345
|
+
week_num += 1
|
|
346
|
+
current = current + 7.days
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def print_monthly_breakdown(event_ranges, time_min, time_max)
|
|
351
|
+
puts "\nBy month:"
|
|
352
|
+
month_num = 1
|
|
353
|
+
current = time_min.to_date.beginning_of_month
|
|
354
|
+
end_date = time_max.to_date
|
|
355
|
+
|
|
356
|
+
while current <= end_date
|
|
357
|
+
month_start = current.beginning_of_month.to_time
|
|
358
|
+
month_end = (current.end_of_month + 1.day).to_time
|
|
359
|
+
period_start = [month_start, time_min].max
|
|
360
|
+
period_end = [month_end, time_max].min
|
|
361
|
+
|
|
362
|
+
mins = minutes_in_period(event_ranges, period_start, period_end)
|
|
363
|
+
hours = (mins / 60).round(1)
|
|
364
|
+
working_days = (mins / 60.0 / HOURS_PER_WORKING_DAY).round(1)
|
|
365
|
+
month_name = current.strftime("%B %Y")
|
|
366
|
+
start_str = format_date_with_day(period_start)
|
|
367
|
+
last_day = (period_end.to_date - 1.day)
|
|
368
|
+
end_str = format_date_with_day(last_day)
|
|
369
|
+
puts " #{month_num}. #{month_name} (#{start_str} - #{end_str}): #{format_hours_and_days(hours, working_days)}"
|
|
370
|
+
month_num += 1
|
|
371
|
+
current = current.next_month.beginning_of_month
|
|
372
|
+
end
|
|
288
373
|
end
|
|
289
374
|
end
|
|
290
375
|
end
|
data/lib/flycal_cli/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flycal-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- flycal-cli
|
|
@@ -79,6 +79,20 @@ dependencies:
|
|
|
79
79
|
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
81
|
version: '0.9'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: activesupport
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '6.0'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '6.0'
|
|
82
96
|
- !ruby/object:Gem::Dependency
|
|
83
97
|
name: webrick
|
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|