dsu 2.4.4 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -0
- data/CHANGELOG.md +42 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -2
- data/Rakefile +6 -0
- data/current_project.bak +4 -0
- data/lib/dsu/cli.rb +24 -6
- data/lib/dsu/crud/json_file.rb +3 -0
- data/lib/dsu/migration/version.rb +1 -1
- data/lib/dsu/models/color_theme.rb +7 -58
- data/lib/dsu/models/configuration.rb +18 -3
- data/lib/dsu/models/entry_group.rb +0 -7
- data/lib/dsu/models/migration_version.rb +0 -1
- data/lib/dsu/models/project.rb +295 -0
- data/lib/dsu/presenters/base_presenter_ex.rb +1 -12
- data/lib/dsu/presenters/export/all_presenter.rb +14 -19
- data/lib/dsu/presenters/export/dates_presenter.rb +17 -20
- data/lib/dsu/presenters/import/all_presenter.rb +20 -25
- data/lib/dsu/presenters/import/dates_presenter.rb +25 -27
- data/lib/dsu/presenters/import/import_entry.rb +22 -0
- data/lib/dsu/presenters/import/import_file.rb +9 -1
- data/lib/dsu/presenters/project/create_presenter.rb +44 -0
- data/lib/dsu/presenters/project/delete_by_number_presenter.rb +54 -0
- data/lib/dsu/presenters/project/delete_presenter.rb +53 -0
- data/lib/dsu/presenters/project/list_presenter.rb +24 -0
- data/lib/dsu/presenters/project/rename_by_number_presenter.rb +63 -0
- data/lib/dsu/presenters/project/rename_presenter.rb +57 -0
- data/lib/dsu/presenters/project/use_by_number_presenter.rb +53 -0
- data/lib/dsu/presenters/project/use_presenter.rb +52 -0
- data/lib/dsu/services/entry_group/exporter_service.rb +22 -5
- data/lib/dsu/services/entry_group/importer_service.rb +41 -8
- data/lib/dsu/services/project/hydrator_service.rb +40 -0
- data/lib/dsu/services/project/rename_service.rb +70 -0
- data/lib/dsu/subcommands/export.rb +4 -2
- data/lib/dsu/subcommands/import.rb +7 -3
- data/lib/dsu/subcommands/project.rb +149 -0
- data/lib/dsu/support/ask.rb +10 -3
- data/lib/dsu/support/color_themable.rb +1 -1
- data/lib/dsu/support/command_hookable.rb +7 -2
- data/lib/dsu/support/descriptable.rb +5 -21
- data/lib/dsu/support/fileable.rb +39 -1
- data/lib/dsu/support/project_file_system.rb +121 -0
- data/lib/dsu/support/short_string.rb +24 -0
- data/lib/dsu/support/time_comparable.rb +2 -0
- data/lib/dsu/support/transform_project_name.rb +24 -0
- data/lib/dsu/validators/project_name_validator.rb +58 -0
- data/lib/dsu/version.rb +1 -1
- data/lib/dsu/views/base_list_view.rb +41 -0
- data/lib/dsu/views/export.rb +60 -6
- data/lib/dsu/views/import.rb +83 -7
- data/lib/dsu/views/import_dates.rb +17 -0
- data/lib/dsu/views/project/create.rb +87 -0
- data/lib/dsu/views/project/delete.rb +96 -0
- data/lib/dsu/views/project/delete_by_number.rb +19 -0
- data/lib/dsu/views/project/list.rb +115 -0
- data/lib/dsu/views/project/rename.rb +98 -0
- data/lib/dsu/views/project/rename_by_number.rb +21 -0
- data/lib/dsu/views/project/use.rb +97 -0
- data/lib/dsu/views/project/use_by_number.rb +19 -0
- data/lib/dsu.rb +2 -10
- data/lib/locales/en/active_record.yml +9 -0
- data/lib/locales/en/commands.yml +9 -3
- data/lib/locales/en/miscellaneous.yml +4 -0
- data/lib/locales/en/services.yml +4 -0
- data/lib/locales/en/subcommands.yml +247 -15
- data/project.bak +0 -0
- metadata +34 -9
- data/lib/dsu/presenters/export/messages.rb +0 -32
- data/lib/dsu/presenters/export/nothing_to_export.rb +0 -13
- data/lib/dsu/presenters/export/service_callable.rb +0 -20
- data/lib/dsu/presenters/import/messages.rb +0 -42
- data/lib/dsu/presenters/import/service_callable.rb +0 -21
data/lib/dsu/views/export.rb
CHANGED
@@ -1,28 +1,82 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../models/color_theme'
|
4
|
-
require_relative '../
|
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
|
20
|
+
return display_nothing_to_export_message if presenter.nothing_to_export?
|
18
21
|
|
19
|
-
response =
|
20
|
-
presenter.
|
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
|
data/lib/dsu/views/import.rb
CHANGED
@@ -1,29 +1,105 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../models/color_theme'
|
4
|
-
require_relative '../
|
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
|
18
|
-
return
|
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 =
|
21
|
-
|
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
|
@@ -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
|