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
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../support/ask'
4
+ require_relative '../../support/color_themable'
5
+ require_relative '../../models/color_theme'
6
+
7
+ module Dsu
8
+ module Views
9
+ module Project
10
+ class Create
11
+ include Support::Ask
12
+ include Support::ColorThemable
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
+ return display_project_errors if presenter.project_errors?
22
+ return display_project_already_exists if presenter.project_already_exists?
23
+
24
+ response = display_project_create_prompt
25
+ if presenter.respond response: response
26
+ display_project_created_message
27
+ else
28
+ display_project_cancelled_message
29
+ end
30
+ rescue StandardError => e
31
+ puts apply_theme(e.message, theme_color: color_theme.error)
32
+ puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :presenter, :color_theme, :options
38
+
39
+ def project_name
40
+ presenter.project_name
41
+ end
42
+
43
+ def display_project_cancelled_message
44
+ message = I18n.t('subcommands.project.messages.cancelled', project_name: project_name)
45
+ puts apply_theme(message, theme_color: color_theme.info)
46
+ end
47
+
48
+ def display_project_create_prompt
49
+ response = ask_while(prompt_with_options(prompt: create_prompt,
50
+ options: create_prompt_options), options: options) do |input|
51
+ message = I18n.t('information.input.try_again', options: create_prompt_options.join(','))
52
+ puts apply_theme(message, theme_color: color_theme.info) unless create_prompt_options.include?(input)
53
+ create_prompt_options.include?(input)
54
+ end
55
+ response == create_prompt_options.first
56
+ end
57
+
58
+ def display_project_created_message
59
+ message = I18n.t('subcommands.project.create.messages.created', project_name: project_name)
60
+ puts apply_theme(message, theme_color: color_theme.success)
61
+ end
62
+
63
+ def display_project_errors
64
+ errors = presenter.project_errors.join("\n")
65
+ puts apply_theme(errors, theme_color: color_theme.error)
66
+ end
67
+
68
+ def display_project_already_exists
69
+ message = I18n.t('subcommands.project.messages.already_exists', project_name: project_name)
70
+ puts apply_theme(message, theme_color: color_theme.error)
71
+ end
72
+
73
+ def create_prompt
74
+ I18n.t('subcommands.project.create.prompts.create_confirm', project_name: project_name)
75
+ end
76
+
77
+ def create_prompt_options
78
+ I18n.t('subcommands.project.create.prompts.create_options')
79
+ end
80
+
81
+ def theme_name
82
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../env'
4
+ require_relative '../../models/color_theme'
5
+ require_relative '../../support/ask'
6
+ require_relative '../../support/color_themable'
7
+
8
+ module Dsu
9
+ module Views
10
+ module Project
11
+ class Delete
12
+ include Support::Ask
13
+ include Support::ColorThemable
14
+
15
+ attr_reader :presenter
16
+
17
+ def initialize(presenter:, options: {})
18
+ @presenter = presenter
19
+ @options = options&.dup || {}
20
+ @color_theme = Models::ColorTheme.find(theme_name: theme_name)
21
+ end
22
+
23
+ def render
24
+ return display_project_does_not_exists if presenter.project_does_not_exist?
25
+ return display_project_errors if presenter.project_errors.any?
26
+ return display_project_is_default if presenter.project_default?
27
+
28
+ response = display_project_delete_prompt
29
+ if presenter.respond response: response
30
+ display_deleted_project_message
31
+ else
32
+ display_delete_project_cancelled_message
33
+ end
34
+ rescue StandardError => e
35
+ puts apply_theme(e.message, theme_color: color_theme.error)
36
+ puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :color_theme, :options
42
+
43
+ def display_project_delete_prompt
44
+ response = ask_while(prompt_with_options(prompt: delete_prompt,
45
+ options: delete_prompt_options), options: options) do |input|
46
+ message = I18n.t('information.input.try_again', options: delete_prompt_options.join(','))
47
+ puts apply_theme(message, theme_color: color_theme.info) unless delete_prompt_options.include?(input)
48
+ delete_prompt_options.include?(input)
49
+ end
50
+ response == delete_prompt_options.first
51
+ end
52
+
53
+ def display_delete_project_cancelled_message
54
+ message = I18n.t('subcommands.project.messages.cancelled', project_name: presenter.project_name)
55
+ puts apply_theme(message, theme_color: color_theme.info)
56
+ end
57
+
58
+ def display_project_errors
59
+ errors = presenter.project_errors.join("\n")
60
+ puts apply_theme(errors, theme_color: color_theme.error)
61
+ end
62
+
63
+ def display_project_does_not_exists
64
+ message = I18n.t('subcommands.project.messages.does_not_exist',
65
+ project_name: presenter.project_name)
66
+ puts apply_theme(message, theme_color: color_theme.error)
67
+ end
68
+
69
+ def display_project_is_default
70
+ message = I18n.t('models.project.errors.delete_default_project',
71
+ project_name: presenter.project_name)
72
+ puts apply_theme(message, theme_color: color_theme.error)
73
+ end
74
+
75
+ def display_deleted_project_message
76
+ message = I18n.t('subcommands.project.delete.messages.deleted',
77
+ project_name: presenter.project_name)
78
+ puts apply_theme(message, theme_color: color_theme.success)
79
+ end
80
+
81
+ def delete_prompt
82
+ I18n.t('subcommands.project.delete.prompts.delete_confirm',
83
+ project_name: presenter.project_name, description: presenter.project_description)
84
+ end
85
+
86
+ def delete_prompt_options
87
+ I18n.t('subcommands.project.delete.prompts.delete_options')
88
+ end
89
+
90
+ def theme_name
91
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'delete'
4
+
5
+ module Dsu
6
+ module Views
7
+ module Project
8
+ class DeleteByNumber < Delete
9
+ private
10
+
11
+ def display_project_does_not_exists
12
+ message = I18n.t('subcommands.project.messages.number_does_not_exist',
13
+ project_number: presenter.project_number)
14
+ puts apply_theme(message, theme_color: color_theme.error)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base_list_view'
4
+
5
+ module Dsu
6
+ module Views
7
+ module Project
8
+ # TODO: I18n.
9
+ class List < Views::BaseListView
10
+ NO_JUSTIFICATION = 4
11
+ PROJECT_JUSTIFICATION = 15
12
+ DEFAULT_JUSTIFICATION = 10
13
+ CURRENT_JUSTIFICATION = 10
14
+ DESCRIPTION_JUSTIFICATION = 10
15
+
16
+ DETAIL_HEADER_STRING = "#{'No.'.ljust(NO_JUSTIFICATION)} " \
17
+ "#{'Project'.ljust(PROJECT_JUSTIFICATION)} " \
18
+ "#{'Default'.center(DEFAULT_JUSTIFICATION)} " \
19
+ "#{'Current'.center(CURRENT_JUSTIFICATION)} " \
20
+ "#{'Description'.ljust(DESCRIPTION_JUSTIFICATION)}".freeze
21
+
22
+ def render
23
+ super do
24
+ return display_no_projects if presenter.projects.none?
25
+
26
+ display_project_list
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def display_project_list
33
+ display_header
34
+ display_detail_header
35
+ display_detail
36
+ display_footer
37
+ end
38
+
39
+ def display_no_projects
40
+ # Should never happen
41
+ message = I18n.t('subcommands.project.messages.no_projects')
42
+ puts apply_theme(message, theme_color: color_theme.info)
43
+ end
44
+
45
+ def display_detail
46
+ presenter.projects.each_with_index do |project, index|
47
+ display_detail_data(
48
+ formatted_index(index: index),
49
+ project.project_name,
50
+ project.default_project?,
51
+ project.current_project?,
52
+ project.description
53
+ )
54
+ end
55
+ end
56
+
57
+ def display_detail_header
58
+ puts apply_theme(DETAIL_HEADER_STRING, theme_color: color_theme.index)
59
+ end
60
+
61
+ def display_detail_data(index, project_name, default_project, current_project, project_desc)
62
+ puts "#{index_detail_data(index)} " \
63
+ "#{project_name_detail_data(project_name)} " \
64
+ "#{project_default_detail_data(default_project)} " \
65
+ "#{project_current_detail_data(current_project)} " \
66
+ "#{project_desc_detail_data(project_desc)}"
67
+ end
68
+
69
+ # def display_detail_data(index, project_name, default_project, current_project, project_desc)
70
+ # puts "#{index_detail_data(index)}|" \
71
+ # "#{project_name_detail_data(project_name)}|" \
72
+ # "#{project_default_detail_data(default_project)}|" \
73
+ # "#{project_current_detail_data(current_project)}|" \
74
+ # "#{project_desc_detail_data(project_desc)}"
75
+ # end
76
+
77
+ def display_footer
78
+ footer = "\nTotal projects: #{presenter.projects.count}"
79
+ puts apply_theme(footer, theme_color: color_theme.footer)
80
+ end
81
+
82
+ def display_header
83
+ header = "Project list\n"
84
+ puts apply_theme(header, theme_color: color_theme.subheader)
85
+ end
86
+
87
+ def index_detail_data(value)
88
+ apply_theme(value.to_s.ljust(NO_JUSTIFICATION), theme_color: color_theme.index)
89
+ end
90
+
91
+ def project_name_detail_data(value)
92
+ apply_theme(value.to_s.ljust(PROJECT_JUSTIFICATION), theme_color: color_theme.body.bold!)
93
+ end
94
+
95
+ def project_default_detail_data(value)
96
+ value = value ? '*' : ' '
97
+ apply_theme(value.to_s.center(DEFAULT_JUSTIFICATION), theme_color: color_theme.body.bold!)
98
+ end
99
+
100
+ def project_current_detail_data(value)
101
+ value = value ? '*' : ' '
102
+ apply_theme(value.to_s.center(CURRENT_JUSTIFICATION), theme_color: color_theme.body.bold!)
103
+ end
104
+
105
+ def project_desc_detail_data(value)
106
+ apply_theme(value.to_s.ljust(DESCRIPTION_JUSTIFICATION), theme_color: color_theme.body)
107
+ end
108
+
109
+ def theme_name
110
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../env'
4
+ require_relative '../../models/color_theme'
5
+ require_relative '../../support/ask'
6
+ require_relative '../../support/color_themable'
7
+
8
+ module Dsu
9
+ module Views
10
+ module Project
11
+ class Rename
12
+ include Support::Ask
13
+ include Support::ColorThemable
14
+
15
+ attr_reader :presenter
16
+
17
+ def initialize(presenter:, options: {})
18
+ @presenter = presenter
19
+ @options = options&.dup || {}
20
+ @color_theme = Models::ColorTheme.find(theme_name: theme_name)
21
+ end
22
+
23
+ def render
24
+ return display_project_does_not_exist if presenter.project_does_not_exist?
25
+ return display_new_project_already_exists if presenter.new_project_already_exists?
26
+ return display_new_project_errors if presenter.new_project_errors.any?
27
+
28
+ response = display_project_rename_prompt
29
+ if presenter.respond response: response
30
+ display_renamed_project_message
31
+ else
32
+ display_rename_project_cancelled_message
33
+ end
34
+ rescue StandardError => e
35
+ puts apply_theme(e.message, theme_color: color_theme.error)
36
+ puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :color_theme, :options
42
+
43
+ def display_project_rename_prompt
44
+ response = ask_while(prompt_with_options(prompt: rename_prompt,
45
+ options: rename_prompt_options), options: options) do |input|
46
+ message = I18n.t('information.input.try_again', options: rename_prompt_options.join(','))
47
+ puts apply_theme(message, theme_color: color_theme.info) unless rename_prompt_options.include?(input)
48
+ rename_prompt_options.include?(input)
49
+ end
50
+ response == rename_prompt_options.first
51
+ end
52
+
53
+ def display_rename_project_cancelled_message
54
+ message = I18n.t('subcommands.project.messages.cancelled')
55
+ puts apply_theme(message, theme_color: color_theme.info)
56
+ end
57
+
58
+ def display_new_project_errors
59
+ errors = presenter.new_project_errors.join("\n")
60
+ puts apply_theme(errors, theme_color: color_theme.error)
61
+ end
62
+
63
+ def display_project_does_not_exist
64
+ message = I18n.t('subcommands.project.messages.does_not_exist',
65
+ project_name: presenter.project_name)
66
+ puts apply_theme(message, theme_color: color_theme.error)
67
+ end
68
+
69
+ def display_new_project_already_exists
70
+ message = I18n.t('subcommands.project.rename.messages.new_project_already_exists',
71
+ new_project_name: presenter.new_project_name)
72
+ puts apply_theme(message, theme_color: color_theme.error)
73
+ end
74
+
75
+ def display_renamed_project_message
76
+ message = I18n.t('subcommands.project.rename.messages.renamed_project',
77
+ project_name: presenter.project_name, new_project_name: presenter.new_project_name)
78
+ puts apply_theme(message, theme_color: color_theme.success)
79
+ end
80
+
81
+ def rename_prompt
82
+ I18n.t('subcommands.project.rename.prompts.rename_confirm',
83
+ project_name: presenter.project_name,
84
+ new_project_name: presenter.new_project_name,
85
+ new_project_description: presenter.new_project_description)
86
+ end
87
+
88
+ def rename_prompt_options
89
+ I18n.t('subcommands.project.rename.prompts.rename_options')
90
+ end
91
+
92
+ def theme_name
93
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../env'
4
+ require_relative '../../models/color_theme'
5
+ require_relative '../../support/ask'
6
+ require_relative '../../support/color_themable'
7
+ require_relative 'rename'
8
+
9
+ module Dsu
10
+ module Views
11
+ module Project
12
+ class RenameByNumber < Rename
13
+ def display_project_does_not_exist
14
+ message = I18n.t('subcommands.project.messages.number_does_not_exist',
15
+ project_number: presenter.project_number)
16
+ puts apply_theme(message, theme_color: color_theme.error)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../env'
4
+ require_relative '../../models/color_theme'
5
+ require_relative '../../support/ask'
6
+ require_relative '../../support/color_themable'
7
+
8
+ module Dsu
9
+ module Views
10
+ module Project
11
+ class Use
12
+ include Support::Ask
13
+ include Support::ColorThemable
14
+
15
+ attr_reader :presenter
16
+
17
+ def initialize(presenter:, options: {})
18
+ @presenter = presenter
19
+ @options = options&.dup || {}
20
+ @color_theme = Models::ColorTheme.find(theme_name: theme_name)
21
+ end
22
+
23
+ def render
24
+ return display_project_does_not_exist if presenter.project_does_not_exist?
25
+ return display_project_already_current_project if presenter.already_current_project?
26
+ return display_project_errors if presenter.project_errors.any?
27
+
28
+ response = display_project_use_prompt
29
+ if presenter.respond response: response
30
+ display_using_project_message
31
+ else
32
+ display_use_project_cancelled_message
33
+ end
34
+ rescue StandardError => e
35
+ puts apply_theme(e.message, theme_color: color_theme.error)
36
+ puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :color_theme, :options
42
+
43
+ def display_project_use_prompt
44
+ response = ask_while(prompt_with_options(prompt: use_prompt,
45
+ options: use_prompt_options), options: options) do |input|
46
+ message = I18n.t('information.input.try_again', options: use_prompt_options.join(','))
47
+ puts apply_theme(message, theme_color: color_theme.info) unless use_prompt_options.include?(input)
48
+ use_prompt_options.include?(input)
49
+ end
50
+ response == use_prompt_options.first
51
+ end
52
+
53
+ def display_use_project_cancelled_message
54
+ message = I18n.t('subcommands.project.messages.cancelled')
55
+ puts apply_theme(message, theme_color: color_theme.info)
56
+ end
57
+
58
+ def display_project_errors
59
+ errors = presenter.project_errors.join("\n")
60
+ puts apply_theme(errors, theme_color: color_theme.error)
61
+ end
62
+
63
+ def display_project_does_not_exist
64
+ message = I18n.t('subcommands.project.messages.does_not_exist',
65
+ project_name: presenter.project_name)
66
+ puts apply_theme(message, theme_color: color_theme.error)
67
+ end
68
+
69
+ def display_using_project_message
70
+ message = I18n.t('subcommands.project.use.messages.using_project',
71
+ project_name: presenter.project_name)
72
+ puts apply_theme(message, theme_color: color_theme.success)
73
+ end
74
+
75
+ def display_project_already_current_project
76
+ message = I18n.t('subcommands.project.messages.already_current_project',
77
+ project_name: presenter.project_name)
78
+ puts apply_theme(message, theme_color: color_theme.success)
79
+ end
80
+
81
+ def use_prompt
82
+ I18n.t('subcommands.project.use.prompts.use_confirm',
83
+ project_name: presenter.project_name,
84
+ description: presenter.project_description)
85
+ end
86
+
87
+ def use_prompt_options
88
+ I18n.t('subcommands.project.use.prompts.use_options')
89
+ end
90
+
91
+ def theme_name
92
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'use'
4
+
5
+ module Dsu
6
+ module Views
7
+ module Project
8
+ class UseByNumber < Use
9
+ private
10
+
11
+ def display_project_does_not_exist
12
+ message = I18n.t('subcommands.project.messages.number_does_not_exist',
13
+ project_number: presenter.project_number)
14
+ puts apply_theme(message, theme_color: color_theme.error)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/dsu.rb CHANGED
@@ -33,14 +33,6 @@ unless Dsu.env.test? || Dsu.env.development?
33
33
  exit 1
34
34
  end
35
35
  end
36
- # TODO: Hack. Integrate this into the migration service
37
- # so that this runs only if the migration version changes.
38
- %w[light.json christmas.json].each do |theme_file|
39
- destination_theme_file_path = File.join(Dsu::Support::Fileable.themes_folder, theme_file)
40
- next if File.exist?(destination_theme_file_path)
41
-
42
- source_theme_file_path = File.join(Dsu::Support::Fileable.seed_data_folder, 'themes', theme_file)
43
- FileUtils.cp(source_theme_file_path, destination_theme_file_path)
44
- puts I18n.t('migrations.information.theme_copied', from: source_theme_file_path, to: destination_theme_file_path)
45
- end
36
+
37
+ Migration::Factory.migrate_if!
46
38
  end
@@ -1,4 +1,13 @@
1
1
  en:
2
+ models:
3
+ project:
4
+ errors:
5
+ already_exists: "Project '%{project_name}' already exists."
6
+ delete_default_project: "Project '%{project_name}' is the default project. Change to a different default project before deleting this project."
7
+ delete_only_project: "Project '%{project_name}' is the only project and cannot be deleted."
8
+ does_not_exist: "Project '%{project_name}' does not exist."
9
+ new_project_already_exists: "Project cannot be renamed to '%{project_name}' because the project already exists."
10
+ project_file_not_exist: "Project file '%{project_file}' does not exist."
2
11
  activerecord:
3
12
  errors:
4
13
  models:
@@ -30,16 +30,18 @@ en:
30
30
  long_desc: |
31
31
  Will add a DSU entry having DESCRIPTION to the date associated with the given OPTION.
32
32
 
33
- $ dsu add [-d DATE|-n|-t|-y] DESCRIPTION
33
+ $ dsu add [-d DATE|MNEMONIC|-n|-t|-y] DESCRIPTION
34
34
 
35
- $ dsu a [-d DATE|-n|-t|-y] DESCRIPTION
35
+ $ dsu a [-d DATE|MNEMONIC|-n|-t|-y] DESCRIPTION
36
36
 
37
37
  OPTIONS:
38
38
 
39
- -d DATE: Adds a DSU entry having DESCRIPTION to the DATE.
39
+ -d DATE|MNEMONIC: Adds a DSU entry having DESCRIPTION to the DATE or date referenced by the MNEMONIC.
40
40
 
41
41
  %{date_option_description}
42
42
 
43
+ %{mnemonic_option_description}
44
+
43
45
  -n: Adds a DSU entry having DESCRIPTION to today's date (`Time.now`).
44
46
 
45
47
  -t: Adds a DSU entry having DESCRIPTION to tomorrow's date (`Time.new.tomorrow`).
@@ -98,6 +100,10 @@ en:
98
100
  key_mappings: l
99
101
  desc: list|l SUBCOMMAND
100
102
  usage: Displays DSU entries for the given SUBCOMMAND
103
+ project:
104
+ key_mappings: p
105
+ desc: project|p SUBCOMMAND
106
+ usage: Manage DSU projects for the given SUBCOMMAND
101
107
  theme:
102
108
  key_mappings: t
103
109
  desc: theme|t SUBCOMMAND
@@ -2,10 +2,12 @@ en:
2
2
  configuration:
3
3
  errors:
4
4
  theme_file_missing: Theme file "%{theme_path}" does not exist.
5
+ project_path_missing: Default project "%{project_folder}" does not exist.
5
6
  errors:
6
7
  error: "Error: %{message}"
7
8
  from_option_invalid: Option -f, [--from=DATE|MNEMONIC] value is invalid ["%{from_option}"]
8
9
  to_option_invalid: Option -t, [--to=DATE|MNEMONIC] value is invalid ["%{to_option}"]
10
+ project_name_invalid: Project name "%{project_name}" is invalid.
9
11
  headers:
10
12
  entry:
11
13
  could_not_be_added: "An error was encountered; the entry could not be added:"
@@ -19,6 +21,8 @@ en:
19
21
  information:
20
22
  dates:
21
23
  through: "%{from} thru %{to}"
24
+ input:
25
+ try_again: "Please try again. Valid options are [%{options}]."
22
26
  migrations:
23
27
  error:
24
28
  failed: "Error running migrations: %{message}"
@@ -8,3 +8,7 @@ en:
8
8
  Run `dsu help config` for more information.
9
9
  messages:
10
10
  editing: "Editing entry group %{formatted_time}..."
11
+ entry_group:
12
+ importer_service:
13
+ errors:
14
+ project_mismatch: The current project "%{current_project_name}" does not match the project "%{import_project_name}" being imported.