dsu 2.4.3 → 3.0.0.alpha.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -0
  3. data/CHANGELOG.md +181 -204
  4. data/Gemfile.lock +13 -13
  5. data/README.md +7 -8
  6. data/Rakefile +6 -0
  7. data/current_project.bak +4 -0
  8. data/lib/dsu/cli.rb +24 -6
  9. data/lib/dsu/crud/json_file.rb +3 -0
  10. data/lib/dsu/migration/version.rb +1 -1
  11. data/lib/dsu/models/color_theme.rb +7 -58
  12. data/lib/dsu/models/configuration.rb +18 -3
  13. data/lib/dsu/models/entry_group.rb +0 -7
  14. data/lib/dsu/models/migration_version.rb +0 -1
  15. data/lib/dsu/models/project.rb +295 -0
  16. data/lib/dsu/presenters/base_presenter_ex.rb +1 -12
  17. data/lib/dsu/presenters/export/all_presenter.rb +14 -19
  18. data/lib/dsu/presenters/export/dates_presenter.rb +17 -20
  19. data/lib/dsu/presenters/import/all_presenter.rb +20 -25
  20. data/lib/dsu/presenters/import/dates_presenter.rb +25 -27
  21. data/lib/dsu/presenters/import/import_entry.rb +22 -0
  22. data/lib/dsu/presenters/import/import_file.rb +9 -1
  23. data/lib/dsu/presenters/project/create_presenter.rb +44 -0
  24. data/lib/dsu/presenters/project/delete_by_number_presenter.rb +54 -0
  25. data/lib/dsu/presenters/project/delete_presenter.rb +53 -0
  26. data/lib/dsu/presenters/project/list_presenter.rb +24 -0
  27. data/lib/dsu/presenters/project/rename_by_number_presenter.rb +63 -0
  28. data/lib/dsu/presenters/project/rename_presenter.rb +57 -0
  29. data/lib/dsu/presenters/project/use_by_number_presenter.rb +53 -0
  30. data/lib/dsu/presenters/project/use_presenter.rb +52 -0
  31. data/lib/dsu/services/entry_group/exporter_service.rb +22 -5
  32. data/lib/dsu/services/entry_group/importer_service.rb +41 -8
  33. data/lib/dsu/services/project/hydrator_service.rb +40 -0
  34. data/lib/dsu/services/project/rename_service.rb +70 -0
  35. data/lib/dsu/subcommands/export.rb +4 -2
  36. data/lib/dsu/subcommands/import.rb +7 -3
  37. data/lib/dsu/subcommands/project.rb +149 -0
  38. data/lib/dsu/support/ask.rb +10 -3
  39. data/lib/dsu/support/color_themable.rb +1 -1
  40. data/lib/dsu/support/command_hookable.rb +7 -2
  41. data/lib/dsu/support/descriptable.rb +5 -21
  42. data/lib/dsu/support/fileable.rb +39 -1
  43. data/lib/dsu/support/project_file_system.rb +121 -0
  44. data/lib/dsu/support/short_string.rb +24 -0
  45. data/lib/dsu/support/time_comparable.rb +2 -0
  46. data/lib/dsu/support/transform_project_name.rb +24 -0
  47. data/lib/dsu/validators/project_name_validator.rb +58 -0
  48. data/lib/dsu/version.rb +1 -1
  49. data/lib/dsu/views/base_list_view.rb +41 -0
  50. data/lib/dsu/views/export.rb +60 -6
  51. data/lib/dsu/views/import.rb +83 -7
  52. data/lib/dsu/views/import_dates.rb +17 -0
  53. data/lib/dsu/views/project/create.rb +87 -0
  54. data/lib/dsu/views/project/delete.rb +96 -0
  55. data/lib/dsu/views/project/delete_by_number.rb +19 -0
  56. data/lib/dsu/views/project/list.rb +115 -0
  57. data/lib/dsu/views/project/rename.rb +98 -0
  58. data/lib/dsu/views/project/rename_by_number.rb +21 -0
  59. data/lib/dsu/views/project/use.rb +97 -0
  60. data/lib/dsu/views/project/use_by_number.rb +19 -0
  61. data/lib/dsu.rb +2 -10
  62. data/lib/locales/en/active_record.yml +9 -0
  63. data/lib/locales/en/commands.yml +9 -3
  64. data/lib/locales/en/miscellaneous.yml +4 -0
  65. data/lib/locales/en/services.yml +4 -0
  66. data/lib/locales/en/subcommands.yml +247 -15
  67. data/project.bak +0 -0
  68. metadata +34 -9
  69. data/lib/dsu/presenters/export/messages.rb +0 -32
  70. data/lib/dsu/presenters/export/nothing_to_export.rb +0 -13
  71. data/lib/dsu/presenters/export/service_callable.rb +0 -20
  72. data/lib/dsu/presenters/import/messages.rb +0 -42
  73. data/lib/dsu/presenters/import/service_callable.rb +0 -21
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'short_string'
4
+
3
5
  module Dsu
4
6
  module Support
5
7
  module Descriptable
6
- DESCRIPTION_MAX_COUNT = 25
7
-
8
8
  class << self
9
9
  def included(base)
10
10
  base.extend(ClassMethods)
@@ -18,26 +18,10 @@ module Dsu
18
18
  end
19
19
 
20
20
  module ClassMethods
21
- def short_description(string:, count: DESCRIPTION_MAX_COUNT, elipsis: '...')
22
- return elipsis unless string.is_a?(String)
23
-
24
- elipsis_length = elipsis.length
25
- count = elipsis_length if count.nil? || count < elipsis_length
26
-
27
- return string if string.length <= count
28
-
29
- tokens = string.split
30
- string = ''
31
-
32
- return "#{tokens.first[0...(count - elipsis_length)]}#{elipsis}" if tokens.count == 1
33
-
34
- tokens.each do |token|
35
- break if string.length + token.length + elipsis_length > count
36
-
37
- string = "#{string} #{token}"
38
- end
21
+ include ShortString
39
22
 
40
- "#{string.strip}#{elipsis}"
23
+ def short_description(string:, count: ShortString::SHORT_STRING_MAX_COUNT, elipsis: '...')
24
+ short_string(string: string, count: count, elipsis: elipsis)
41
25
  end
42
26
  end
43
27
  end
@@ -26,7 +26,8 @@ module Dsu
26
26
  # Entries
27
27
 
28
28
  def entries_folder
29
- File.join(dsu_folder, 'entries')
29
+ project_folder = project_folder_for(project_name: Models::Project.current_project_name)
30
+ File.join(project_folder, 'entries')
30
31
  end
31
32
 
32
33
  def entries_file_name(time:, file_name_format: nil)
@@ -88,6 +89,43 @@ module Dsu
88
89
  File.join(gem_dir, 'lib/seed_data')
89
90
  end
90
91
 
92
+ # Projects
93
+
94
+ # Returns the folder where all the projects are stored.
95
+ def projects_folder
96
+ File.join(dsu_folder, 'projects')
97
+ end
98
+
99
+ # Current project
100
+
101
+ # Contains the name of the file that contains the current
102
+ # dsu project currently being used.
103
+ def current_project_file_name
104
+ 'current_project.json'
105
+ end
106
+
107
+ # The complete path to the current project file.
108
+ def current_project_file
109
+ File.join(dsu_folder, current_project_file_name)
110
+ end
111
+
112
+ # Project helpers
113
+
114
+ # Returns the path of the project with the given name.
115
+ def project_folder_for(project_name:)
116
+ raise I18n.t('errors.project_name_invalid', project_name: '{{blank}}') if project_name.blank?
117
+
118
+ File.join(projects_folder, project_name)
119
+ end
120
+ alias project_folder project_folder_for
121
+
122
+ def project_file_for(project_name:)
123
+ project_folder = project_folder_for(project_name: project_name)
124
+
125
+ File.join(project_folder, 'project.json')
126
+ end
127
+ alias project_file project_file_for
128
+
91
129
  extend self # rubocop:disable Style/ModuleFunction
92
130
  end
93
131
  end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'pathname'
5
+ require_relative '../crud/json_file'
6
+ require_relative '../migration/version'
7
+ require_relative '../models/configuration'
8
+ require_relative 'fileable'
9
+
10
+ module Dsu
11
+ module Support
12
+ module ProjectFileSystem
13
+ class << self
14
+ def included(base)
15
+ base.extend(ClassMethods)
16
+ end
17
+ end
18
+
19
+ def exist?
20
+ self.class.project_file_exist?(project_name: project_name)
21
+ end
22
+ alias persisted? exist?
23
+
24
+ def project_initialized?
25
+ self.class.project_initialized?(project_name: project_name)
26
+ end
27
+
28
+ def project_number
29
+ self.class.project_number_for(project_name: project_name)
30
+ end
31
+
32
+ module ClassMethods
33
+ include Fileable
34
+
35
+ # Returns the currently selected (used) project name
36
+ # from dsu/current_project.json
37
+ def current_project_name
38
+ Crud::JsonFile.read!(file_path: current_project_file).fetch(:project_name)
39
+ end
40
+
41
+ def default_project_name
42
+ Models::Configuration.new.default_project
43
+ end
44
+
45
+ def initialize_project(project_name:)
46
+ return if project_initialized?(project_name: project_name)
47
+
48
+ # TODO: Don't know if I like this here.
49
+ unless current_project_file_exist?
50
+ file_data = {
51
+ version: Dsu::Migration::VERSION,
52
+ project_name: default_project_name
53
+ }
54
+ Crud::JsonFile.write!(file_data: file_data, file_path: current_project_file)
55
+ end
56
+
57
+ # Creates dsu/projects/<project_name>
58
+ FileUtils.mkdir_p(project_folder_for(project_name: project_name))
59
+ end
60
+
61
+ def project_initialized?(project_name:)
62
+ # Checking these files, checks all the containing folders also
63
+ current_project_file_exist? &&
64
+ project_folder_exist?(project_name: project_name)
65
+ end
66
+
67
+ # Does dsu/projects/<project_name>/project.json file exist?
68
+ def project_file_exist?(project_name:)
69
+ project_file_path = project_file_for(project_name: project_name)
70
+ File.exist?(project_file_path)
71
+ end
72
+ alias exist? project_file_exist?
73
+ alias persisted? project_file_exist?
74
+
75
+ # Does dsu/current_project.json file exist?
76
+ def current_project_file_exist?
77
+ File.exist?(current_project_file)
78
+ end
79
+ alias current_project_file_persisted? current_project_file_exist?
80
+
81
+ # Does dsu/projects folder exist?
82
+ def projects_folder_exist?
83
+ Dir.exist?(projects_folder)
84
+ end
85
+
86
+ # Does dsu/projects/<project_name> folder exist?
87
+ def project_folder_exist?(project_name:)
88
+ Dir.exist?(project_folder_for(project_name: project_name))
89
+ end
90
+
91
+ def project_metadata
92
+ project_folder_names.each_with_index.with_object([]) do |(project_name, index), array|
93
+ array << {
94
+ project_number: index + 1,
95
+ project_name: project_name,
96
+ current_project: project_name == current_project_name,
97
+ default_projet: project_name == default_project_name
98
+ }
99
+ end
100
+ end
101
+
102
+ def project_number_for(project_name:)
103
+ project_metadata.find do |metadata|
104
+ metadata[:project_name] == project_name
105
+ end&.[](:project_number) || -1
106
+ end
107
+
108
+ private
109
+
110
+ def project_folder_names
111
+ Pathname.new(projects_folder)
112
+ .children
113
+ .select(&:directory?)
114
+ .map(&:basename)
115
+ .map(&:to_s)
116
+ .sort { |a, b| a.casecmp(b) }
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dsu
4
+ module Support
5
+ module ShortString
6
+ SHORT_STRING_MAX_COUNT = 25
7
+
8
+ module_function
9
+
10
+ def short_string(string:, count: SHORT_STRING_MAX_COUNT, elipsis: '...')
11
+ return '' if string.blank?
12
+ return string if string.length <= count
13
+
14
+ # Trim to max count and cut at the last space within the limit
15
+ trimmed_string = string[0...count].rpartition(' ')[0]
16
+
17
+ # If no space found, trim by characters
18
+ trimmed_string = string[0...(count - elipsis.length)] if trimmed_string.empty? && !string.empty?
19
+
20
+ "#{trimmed_string}#{elipsis}"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -5,6 +5,8 @@ module Dsu
5
5
  module TimeComparable
6
6
  TIME_COMPARABLE_FORMAT_SPECIFIER = '%Y%m%d'
7
7
 
8
+ module_function
9
+
8
10
  def time_equal?(other_time:)
9
11
  time_equal_compare_string_for(time: time) == time_equal_compare_string_for(time: other_time)
10
12
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dsu
4
+ module Support
5
+ module TransformProjectName
6
+ TRANSFORM_PROJECT_NAME_REGEX = %r{[^/\w\s]|_}
7
+ TRANSFORM_PROJECT_NAME_SEPARATOR = '-'
8
+
9
+ module_function
10
+
11
+ def transform_project_name(project_name, options: {})
12
+ normalized_name = project_name
13
+ .gsub(TRANSFORM_PROJECT_NAME_REGEX, ' ') # Replace non-word characters and underscores with space
14
+ .strip # Remove leading and trailing spaces
15
+ .squeeze(' ') # Convert consecutive spaces to a single space
16
+ .tr(' ', TRANSFORM_PROJECT_NAME_SEPARATOR) # Replace spaces with hyphens
17
+ .squeeze(TRANSFORM_PROJECT_NAME_SEPARATOR) # Ensure no consecutive hyphens
18
+
19
+ normalized_name.downcase! if options[:downcase]
20
+ normalized_name
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../support/field_errors'
4
+ require_relative '../support/short_string'
5
+
6
+ # https://guides.rubyonrails.org/active_record_validations.html#validates-with
7
+ module Dsu
8
+ module Validators
9
+ # TODO: I18n.
10
+ class ProjectNameValidator < ActiveModel::Validator
11
+ include Support::FieldErrors
12
+ include Support::ShortString
13
+
14
+ def validate(record)
15
+ unless record.project_name.is_a?(String)
16
+ record.errors.add(:project_name, 'is the wrong object type. ' \
17
+ "\"String\" was expected, but \"#{record.project.class}\" was received.")
18
+ return
19
+ end
20
+
21
+ unless record.project_name.present?
22
+ record.errors.add(:project_name, :blank, '')
23
+
24
+ return
25
+ end
26
+
27
+ validate_project_name record
28
+ end
29
+
30
+ private
31
+
32
+ def validate_project_name(record)
33
+ project_name = record.project_name
34
+
35
+ return if project_name.length.between?(min_project_name_length(record), max_project_name_length(record))
36
+
37
+ if project_name.length < min_project_name_length(record)
38
+ # TODO: I18n.
39
+ record.errors.add(:project_name, "is too short: \"#{record.project_name}\" " \
40
+ "(minimum is #{min_project_name_length(record)} characters).")
41
+ elsif project_name.length > max_project_name_length(record)
42
+ # TODO: I18n.
43
+ short_project_name = short_string(string: project_name, count: max_project_name_length(record))
44
+ record.errors.add(:project_name, "is too long: \"#{short_project_name}\" " \
45
+ "(maximum is #{max_project_name_length(record)} characters).")
46
+ end
47
+ end
48
+
49
+ def min_project_name_length(record)
50
+ record.class::MIN_PROJECT_NAME_LENGTH
51
+ end
52
+
53
+ def max_project_name_length(record)
54
+ record.class::MAX_PROJECT_NAME_LENGTH
55
+ end
56
+ end
57
+ end
58
+ end
data/lib/dsu/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Dsu
4
4
  VERSION_REGEX = /\A\d+\.\d+\.\d+(\.(alpha|rc)\.\d+)?\z/
5
- VERSION = '2.4.3'
5
+ VERSION = '3.0.0.alpha.0'
6
6
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../env'
4
+ require_relative '../models/color_theme'
5
+ require_relative '../support/color_themable'
6
+
7
+ module Dsu
8
+ module Views
9
+ class BaseListView
10
+ include Support::ColorThemable
11
+
12
+ attr_reader :presenter
13
+
14
+ def initialize(presenter:, options: {})
15
+ @presenter = presenter
16
+ @options = options&.dup || {}
17
+ @color_theme = Models::ColorTheme.find(theme_name: theme_name)
18
+ end
19
+
20
+ def render
21
+ yield
22
+ rescue StandardError => e
23
+ puts apply_theme(e.message, theme_color: color_theme.error)
24
+ puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :color_theme, :options
30
+
31
+ def theme_name
32
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
33
+ end
34
+
35
+ def formatted_index(index:)
36
+ apply_theme("#{format('%02s', index + 1)}. ",
37
+ theme_color: color_theme.index)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,28 +1,82 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../models/color_theme'
4
- require_relative '../models/configuration'
4
+ require_relative '../support/ask'
5
5
  require_relative '../support/color_themable'
6
6
 
7
7
  module Dsu
8
8
  module Views
9
9
  class Export
10
+ include Support::Ask
10
11
  include Support::ColorThemable
11
12
 
12
- def initialize(presenter:)
13
+ def initialize(presenter:, options:)
13
14
  @presenter = presenter
15
+ @options = options&.dup || {}
16
+ @color_theme = Models::ColorTheme.find(theme_name: theme_name)
14
17
  end
15
18
 
16
19
  def render
17
- return presenter.display_nothing_to_export_message if presenter.nothing_to_export?
20
+ return display_nothing_to_export_message if presenter.nothing_to_export?
18
21
 
19
- response = presenter.display_export_prompt
20
- presenter.render response: response
22
+ response = display_export_prompt
23
+ if presenter.respond response: response
24
+ display_exported_message
25
+ display_exported_to_message(file_path: presenter.export_file_path)
26
+ else
27
+ display_cancelled_message
28
+ end
29
+ rescue StandardError => e
30
+ puts apply_theme(e.message, theme_color: color_theme.error)
31
+ puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
21
32
  end
22
33
 
23
34
  private
24
35
 
25
- attr_reader :presenter
36
+ attr_reader :presenter, :color_theme, :options
37
+
38
+ def project_name
39
+ presenter.project_name
40
+ end
41
+
42
+ def display_export_prompt
43
+ response = ask_while(prompt_with_options(prompt: export_prompt,
44
+ options: export_prompt_options), options: options) do |input|
45
+ message = I18n.t('information.input.try_again', options: export_prompt_options.join(','))
46
+ puts apply_theme(message, theme_color: color_theme.info) unless export_prompt_options.include?(input)
47
+ export_prompt_options.include?(input)
48
+ end
49
+ response == export_prompt_options.first
50
+ end
51
+
52
+ def display_cancelled_message
53
+ puts apply_theme(I18n.t('subcommands.export.messages.cancelled'), theme_color: color_theme.info)
54
+ end
55
+
56
+ def display_exported_message
57
+ puts apply_theme(I18n.t('subcommands.export.messages.exported'), theme_color: color_theme.success)
58
+ end
59
+
60
+ def display_exported_to_message(file_path:)
61
+ puts apply_theme(I18n.t('subcommands.export.messages.exported_to', file_path: file_path),
62
+ theme_color: color_theme.success)
63
+ end
64
+
65
+ def display_nothing_to_export_message
66
+ puts apply_theme(I18n.t('subcommands.export.messages.nothing_to_export'), theme_color: color_theme.info)
67
+ end
68
+
69
+ def export_prompt
70
+ I18n.t('subcommands.export.prompts.export_all_confirm', count: presenter.entry_group_count)
71
+ end
72
+
73
+ def export_prompt_options
74
+ I18n.t('subcommands.export.prompts.options')
75
+ end
76
+
77
+ def theme_name
78
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
79
+ end
26
80
  end
27
81
  end
28
82
  end
@@ -1,29 +1,105 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../models/color_theme'
4
- require_relative '../models/configuration'
4
+ require_relative '../support/ask'
5
5
  require_relative '../support/color_themable'
6
6
 
7
7
  module Dsu
8
8
  module Views
9
9
  class Import
10
+ include Support::Ask
10
11
  include Support::ColorThemable
11
12
 
12
- def initialize(presenter:)
13
+ def initialize(presenter:, options:)
13
14
  @presenter = presenter
15
+ @options = options&.dup || {}
16
+ @color_theme = Models::ColorTheme.find(theme_name: theme_name)
14
17
  end
15
18
 
16
19
  def render
17
- return presenter.display_import_file_not_exist_message unless presenter.import_file_path_exist?
18
- return presenter.display_nothing_to_import_message if presenter.nothing_to_import?
20
+ return display_import_file_not_exist_message unless presenter.import_file_path_exist?
21
+ return display_nothing_to_import_message if presenter.nothing_to_import?
19
22
 
20
- response = presenter.display_import_prompt
21
- presenter.render response: response
23
+ response = display_import_prompt
24
+ return display_cancelled_message unless response
25
+
26
+ response = display_project_override_prompt if presenter.overriding_project?
27
+ return display_cancelled_message unless response
28
+
29
+ display_import_messages presenter.respond
30
+ rescue StandardError => e
31
+ puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
32
+ message = I18n.t('subcommands.import.messages.import_error_raised', error: e.message)
33
+ puts apply_theme(message, theme_color: color_theme.error)
22
34
  end
23
35
 
24
36
  private
25
37
 
26
- attr_reader :presenter
38
+ attr_reader :presenter, :color_theme, :options
39
+
40
+ def display_import_prompt
41
+ response = ask_while(prompt_with_options(prompt: import_prompt,
42
+ options: import_prompt_options), options: options) do |input|
43
+ message = I18n.t('information.input.try_again', options: import_prompt_options.join(','))
44
+ puts apply_theme(message, theme_color: color_theme.info) unless import_prompt_options.include?(input)
45
+ import_prompt_options.include?(input)
46
+ end
47
+ response == import_prompt_options.first
48
+ end
49
+
50
+ def display_project_override_prompt
51
+ response = ask_while(prompt_with_options(prompt: project_override_prompt,
52
+ options: import_prompt_options), options: options) do |input|
53
+ message = I18n.t('information.input.try_again', options: import_prompt_options.join(','))
54
+ puts apply_theme(message, theme_color: color_theme.info) unless import_prompt_options.include?(input)
55
+ import_prompt_options.include?(input)
56
+ end
57
+ response == import_prompt_options.first
58
+ end
59
+
60
+ def display_cancelled_message
61
+ puts apply_theme(I18n.t('subcommands.import.messages.cancelled'), theme_color: color_theme.info)
62
+ end
63
+
64
+ def display_nothing_to_import_message
65
+ puts apply_theme(I18n.t('subcommands.import.messages.nothing_to_import'), theme_color: color_theme.info)
66
+ end
67
+
68
+ def import_prompt
69
+ I18n.t('subcommands.import.prompts.import_all_confirm',
70
+ count: presenter.import_entry_groups_count, project: presenter.project_name)
71
+ end
72
+
73
+ def project_override_prompt
74
+ I18n.t('subcommands.import.prompts.project_override_confirm')
75
+ end
76
+
77
+ def import_prompt_options
78
+ I18n.t('subcommands.import.prompts.options')
79
+ end
80
+
81
+ def display_import_file_not_exist_message
82
+ puts apply_theme(I18n.t('subcommands.import.messages.file_not_exist',
83
+ file_path: presenter.import_file_path), theme_color: color_theme.info)
84
+ end
85
+
86
+ def display_import_messages(import_results)
87
+ import_results.each_pair do |entry_group_date, errors|
88
+ if errors.empty?
89
+ puts apply_theme(I18n.t('subcommands.import.messages.import_success',
90
+ date: entry_group_date), theme_color: color_theme.success)
91
+ else
92
+ errors.each do |error|
93
+ puts apply_theme(I18n.t('subcommands.import.messages.import_error',
94
+ date: entry_group_date, error: error), theme_color: color_theme.error)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ def theme_name
101
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
102
+ end
27
103
  end
28
104
  end
29
105
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'import'
4
+
5
+ module Dsu
6
+ module Views
7
+ class ImportDates < Import
8
+ private
9
+
10
+ def import_prompt
11
+ I18n.t('subcommands.import.prompts.import_dates_confirm',
12
+ from: presenter.from.to_date, to: presenter.to.to_date,
13
+ count: presenter.import_entry_groups_count, project: presenter.project_name)
14
+ end
15
+ end
16
+ end
17
+ end