kuppayam 0.1.5 → 0.1.6dev2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -0
  3. data/app/assets/images/{kuppayam/favicon.png → favicon.png} +0 -0
  4. data/app/assets/images/{kuppayam/logo.png → logo.png} +0 -0
  5. data/app/assets/javascripts/kuppayam.js +3 -0
  6. data/app/assets/javascripts/kuppayam/utilities.js +28 -0
  7. data/app/assets/stylesheets/kuppayam.css +1 -0
  8. data/app/assets/stylesheets/kuppayam/custom.css +4 -0
  9. data/app/controllers/kuppayam/base_controller.rb +14 -4
  10. data/app/controllers/kuppayam/documents_controller.rb +24 -0
  11. data/app/controllers/kuppayam/images_controller.rb +41 -1
  12. data/app/helpers/breadcrumbs_helper.rb +1 -1
  13. data/app/helpers/filter_helper.rb +9 -3
  14. data/app/helpers/image_helper.rb +11 -3
  15. data/app/helpers/kuppayam_helper.rb +2 -2
  16. data/app/helpers/meta_tags_helper.rb +0 -4
  17. data/app/helpers/notification_helper.rb +6 -6
  18. data/app/helpers/render_helper.rb +11 -2
  19. data/app/helpers/resource_helper.rb +23 -9
  20. data/app/models/document/base.rb +13 -15
  21. data/app/models/document/import_data_file.rb +14 -0
  22. data/app/models/document/import_report_file.rb +8 -0
  23. data/app/models/image/base.rb +12 -14
  24. data/app/models/import_data.rb +19 -2
  25. data/app/models/kuppayam/application_record.rb +3 -0
  26. data/app/uploaders/document_uploader.rb +4 -4
  27. data/app/uploaders/image_uploader.rb +1 -1
  28. data/app/uploaders/import_data_uploader.rb +15 -0
  29. data/app/views/kuppayam/documents/create.html.erb +1 -1
  30. data/app/views/kuppayam/documents/edit.js.erb +1 -1
  31. data/app/views/kuppayam/documents/new.js.erb +1 -1
  32. data/app/views/kuppayam/documents/update.html.erb +1 -1
  33. data/app/views/kuppayam/filters/_display_dropdown_filters.html.erb +11 -0
  34. data/app/views/kuppayam/filters/_display_filters.html.erb +29 -0
  35. data/app/views/kuppayam/http_status/404.html.erb +1 -0
  36. data/app/views/kuppayam/images/_form.html.erb +1 -1
  37. data/app/views/kuppayam/images/_index.html.erb +17 -20
  38. data/app/views/kuppayam/images/_show.html.erb +32 -0
  39. data/app/views/kuppayam/images/create.html.erb +4 -4
  40. data/app/views/kuppayam/images/crop.html.erb +1 -1
  41. data/app/views/kuppayam/images/destroy.js.erb +19 -0
  42. data/app/views/kuppayam/images/edit.js.erb +3 -3
  43. data/app/views/kuppayam/images/index.html.erb +8 -1
  44. data/app/views/kuppayam/images/new.js.erb +1 -1
  45. data/app/views/kuppayam/images/update.html.erb +5 -5
  46. data/app/views/kuppayam/import_data/new.js.erb +1 -1
  47. data/app/views/kuppayam/import_data/update.html.erb +1 -1
  48. data/app/views/kuppayam/workflows/parrot/create.js.erb +11 -6
  49. data/app/views/kuppayam/workflows/parrot/edit.js.erb +1 -1
  50. data/app/views/kuppayam/workflows/parrot/new.js.erb +2 -2
  51. data/app/views/kuppayam/workflows/parrot/row.js.erb +1 -1
  52. data/app/views/kuppayam/workflows/parrot/update.js.erb +10 -5
  53. data/app/views/kuppayam/workflows/peacock/create.js.erb +12 -7
  54. data/app/views/kuppayam/workflows/peacock/edit.js.erb +2 -2
  55. data/app/views/kuppayam/workflows/peacock/new.js.erb +2 -2
  56. data/app/views/kuppayam/workflows/peacock/row.js.erb +1 -1
  57. data/app/views/kuppayam/workflows/peacock/update.js.erb +11 -6
  58. data/app/views/layouts/kuppayam/_footer.html.erb +1 -0
  59. data/app/views/layouts/kuppayam/_head.html.erb +11 -2
  60. data/app/views/layouts/kuppayam/_heading.html.erb +11 -2
  61. data/app/views/layouts/kuppayam/_horizontal_menu.html.erb +932 -0
  62. data/app/views/layouts/kuppayam/_sidebar.html.erb +5 -2
  63. data/app/views/layouts/kuppayam/admin.html.erb +63 -6
  64. data/app/views/layouts/kuppayam/blank.html.erb +62 -5
  65. data/app/views/layouts/kuppayam/document_upload.html.erb +3 -2
  66. data/app/views/layouts/kuppayam/image_upload.html.erb +3 -2
  67. data/app/views/layouts/kuppayam/layout_horizontal_menu.html.erb +116 -0
  68. data/app/views/layouts/kuppayam/print_a4.html.erb +32 -0
  69. data/app/views/layouts/kuppayam/user.html.erb +120 -0
  70. data/config/initializers/importer.rb +303 -0
  71. data/config/initializers/validators.rb +78 -0
  72. data/config/locales/kuppayam/general.yml +1 -0
  73. data/config/routes.rb +1 -1
  74. data/db/migrate/20170000000000_create_images.rb +1 -0
  75. data/db/migrate/20170000000001_create_documents.rb +2 -1
  76. data/db/migrate/20170000000002_create_import_data.rb +2 -2
  77. data/lib/kuppayam/action_view/form_helper.rb +1 -1
  78. data/lib/kuppayam/action_view/theme_helper.rb +8 -2
  79. data/lib/kuppayam/engine.rb +2 -0
  80. data/lib/kuppayam/version.rb +1 -1
  81. data/lib/tasks/template.rake +72 -0
  82. data/lib/tasks/test_import.rake +40 -0
  83. data/vendor/assets/stylesheets/custom.css +0 -0
  84. metadata +76 -16
  85. data/app/views/kuppayam/images/_action_buttons.html.erb +0 -14
  86. data/app/views/layouts/kuppayam/_overlays.html.erb +0 -47
  87. data/config/initializers/kuppayam_validators.rb +0 -76
  88. data/lib/tasks/kuppayam_tasks.rake +0 -4
@@ -0,0 +1,303 @@
1
+ # require 'axlsx'
2
+ require 'colorized_string'
3
+ # require 'roo'
4
+ require 'benchmark'
5
+ require 'iconv'
6
+
7
+ module Kuppayam
8
+
9
+ module Importer
10
+
11
+ class ErrorHash
12
+
13
+ attr_accessor :warnings,
14
+ :errors
15
+
16
+ def initialize
17
+ @warnings = []
18
+ @errors = []
19
+ end
20
+
21
+ def warnings?
22
+ @warnings.any?
23
+ end
24
+
25
+ def errors?
26
+ @errors.any?
27
+ end
28
+
29
+ def print_dot
30
+ if self.warnings?
31
+ print ".".yellow
32
+ elsif self.errors?
33
+ print ".".red
34
+ else
35
+ print ".".green
36
+ end
37
+ end
38
+
39
+ def print_all
40
+ self.warnings.each do |item|
41
+ puts "Summary: #{item[:summary]}".yellow
42
+ puts "Details: #{item[:details]}".yellow if item[:details]
43
+ puts "Stack Trace: #{item[:stack_trace]}".yellow if item[:stack_trace]
44
+ puts ""
45
+ end
46
+ self.errors.each do |item|
47
+ puts "Summary: #{item[:summary]}".red
48
+ puts "Details: #{item[:details]}".red if item[:details]
49
+ puts "Stack Trace: #{item[:stack_trace]}".red if item[:stack_trace]
50
+ puts ""
51
+ end
52
+ end
53
+ end
54
+
55
+ class DataError
56
+ attr_accessor :errors, :columns
57
+
58
+ def initialize
59
+ @errors = {}
60
+ @columns = []
61
+ end
62
+
63
+ def add_column_error(name, value, errors, row_number)
64
+ if @errors[row_number].blank?
65
+ @errors[row_number] = {
66
+ name => { value: value, errors: errors }
67
+ }
68
+ else
69
+ @errors[row_number][name] = { value: value, errors: errors }
70
+ end
71
+ end
72
+
73
+ def generate_error_file
74
+
75
+ axlsx_package = Axlsx::Package.new
76
+ wb = axlsx_package.workbook
77
+
78
+ normal_cell = s.add_style :bg_color => "FFFFFF", :fg_color => "4B4B4B", :sz => 14, :alignment => { :horizontal=> :center }
79
+ error_cell = s.add_style :bg_color => "FFE2E2", :fg_color => "4B4B4B", :sz => 14, :alignment => { :horizontal=> :center }
80
+
81
+ wb.add_worksheet(:name => "Errors") do |sheet|
82
+
83
+ sheet.add_row self.columns
84
+
85
+ self.errors.each do |row_number, values|
86
+ row_data = self.columns.map{|col| values[col][:value] }
87
+ sheet.add_row row_data
88
+ end
89
+
90
+ end
91
+ axlsx_package.serialize("tmp/example.xlsx")
92
+ end
93
+ end
94
+
95
+ def clean_string(str, label=nil)
96
+ begin
97
+ cleaned_str = str.gsub(/\r/, "").gsub(/\n/, "").squeeze(" ")
98
+ cleaned_str = Iconv.conv('UTF-8', 'ISO-8859-1//TRANSLIT//IGNORE', cleaned_str)
99
+ rescue Exception => e
100
+ puts "Error while cleaning #{label ? label : 'string'} '#{str}' - #{e.message}".red
101
+ end
102
+ end
103
+
104
+ def check_file_type_and_import(path, single_transaction=true, verbose=true)
105
+ if File.exists?(path)
106
+ if File.extname(path) == ".csv"
107
+ puts "CSV file found at '#{path.to_s}'.".green if verbose
108
+ self.import_from_csv(path.to_s, single_transaction, verbose)
109
+ elsif File.extname(path) == ".xlsx"
110
+ puts "XSLX file found at '#{path.to_s}'.".green if verbose
111
+ self.import_from_xslx(path.to_s, single_transaction, verbose)
112
+ else
113
+ puts "Unsupported File encountered'#{path.to_s}'.".red if verbose
114
+ return
115
+ end
116
+ else
117
+ puts "Import File not found at '#{path.to_s}'.".red if verbose
118
+ end
119
+ end
120
+
121
+ def import_from_sql(sql_path, verbose=true)
122
+
123
+ errors = []
124
+
125
+ print_memory_usage do
126
+ print_time_spent do
127
+ sum = 0
128
+
129
+ CSV.foreach(csv_path, headers: true, header_converters: :symbol) do |row|
130
+ obj, error_object = save_row_data(row)
131
+ errors << error_object if error_object
132
+ error_object.print_dot if error_object && verbose
133
+ sum += 1
134
+ end
135
+
136
+ puts "Sum: #{sum}"
137
+ end
138
+ end
139
+
140
+ if verbose
141
+ puts ""
142
+ errors.each do |error_object|
143
+ error_object.print_all if error_object
144
+ end
145
+ end
146
+ end
147
+
148
+ def import_from_csv(csv_path, single_transaction=true, verbose=true)
149
+ errors = []
150
+ sum = 0
151
+
152
+ # , encoding: 'windows-1251:utf-8', :row_sep => :auto
153
+ if single_transaction
154
+ ActiveRecord::Base.transaction do
155
+ CSV.foreach(csv_path, headers: true, header_converters: :symbol, skip_blanks: true) do |row|
156
+ obj, error_object = save_row_data(row)
157
+ errors << error_object if error_object
158
+ error_object.print_dot if error_object && verbose
159
+ sum += 1
160
+ end
161
+ end
162
+ else
163
+ CSV.foreach(csv_path, headers: true, header_converters: :symbol, skip_blanks: true) do |row|
164
+ obj, error_object = save_row_data(row)
165
+ errors << error_object if error_object
166
+ error_object.print_dot if error_object && verbose
167
+ sum += 1
168
+ end
169
+ end
170
+ puts "\tScanned #{sum} rows".yellow
171
+
172
+ if verbose
173
+ puts ""
174
+ errors.each do |error_object|
175
+ error_object.print_all if error_object
176
+ end
177
+ end
178
+ end
179
+
180
+ def import_from_xslx(xlsx_path, single_transaction = true, verbose=true)
181
+ xlsx = Roo::Spreadsheet.open(xlsx_path, extension: :xlsx)
182
+ sheet = xlsx.sheet(0)
183
+ headers = sheet.row(1)
184
+
185
+ errors = []
186
+ if single_transaction
187
+ ActiveRecord::Base.transaction do
188
+ 2.upto(xlsx.last_row) do |line|
189
+ row_hash = ActiveSupport::HashWithIndifferentAccess[headers.zip(xlsx.row(line))]
190
+ obj, error_object = save_row_data(row_hash)
191
+ errors << error_object if error_object
192
+ error_object.print_dot if error_object && verbose
193
+ end
194
+ end
195
+ else
196
+ 2.upto(xlsx.last_row) do |line|
197
+ row_hash = ActiveSupport::HashWithIndifferentAccess[headers.zip(xlsx.row(line))]
198
+ obj, error_object = save_row_data(row_hash)
199
+ errors << error_object if error_object
200
+ error_object.print_dot if error_object && verbose
201
+ end
202
+ end
203
+
204
+ if verbose
205
+ puts ""
206
+ errors.each do |error_object|
207
+ error_object.print_all if error_object
208
+ end
209
+ end
210
+ end
211
+
212
+ def walk_and_import(start, single_transaction=true, verbose=true)
213
+ puts "Importing Files from the Folder '#{start.to_s}'".yellow if verbose
214
+ Dir.foreach(start) do |x|
215
+ next if x.starts_with?("master")
216
+ next unless x.ends_with?(".csv")
217
+ path = File.join(start, x)
218
+ if x == "." or x == ".."
219
+ next
220
+ elsif File.directory?(path)
221
+ self.walk_and_import(path, single_transaction, verbose)
222
+ else
223
+ self.check_file_type_and_import(path, single_transaction, verbose)
224
+ end
225
+ end
226
+ end
227
+
228
+ def import_data_recursively(path, single_transaction=true, verbose=true)
229
+ print_memory_usage do
230
+ print_time_spent do
231
+ if Dir.exists?(path)
232
+ self.walk_and_import(path, single_transaction, verbose)
233
+ else
234
+ puts "Import Folder not found: '#{path.to_s}'.".red if verbose
235
+ end
236
+ end
237
+ end
238
+ end
239
+
240
+ def import_data_file(path, single_transaction=true, verbose=true)
241
+ print_memory_usage do
242
+ print_time_spent do
243
+ check_file_type_and_import(path, single_transaction, verbose)
244
+ end
245
+ end
246
+ end
247
+
248
+ def print_memory_usage
249
+ memory_before = `ps -o rss= -p #{Process.pid}`.to_i
250
+ yield
251
+ memory_after = `ps -o rss= -p #{Process.pid}`.to_i
252
+
253
+ puts "Memory: #{((memory_after - memory_before) / 1024.0).round(2)} MB"
254
+ end
255
+
256
+ def print_time_spent
257
+ time = Benchmark.realtime do
258
+ yield
259
+ end
260
+
261
+ puts "Time: #{time.round(2)}"
262
+ end
263
+
264
+ def csv_foreach_backup_code
265
+ # batch_size = 1000
266
+
267
+ # File.open(csv_path) do |file|
268
+ # file.lazy.drop(header_lines).each_slice(batch_size) do |lines|
269
+ # puts lines
270
+ # end
271
+ # end
272
+
273
+ # File.open(csv_path) do |file|
274
+ # binding.pry
275
+ # headers = file.first
276
+ # file.lazy.each_slice(batch_size) do |lines|
277
+ # csv_rows = CSV.parse(lines.join, write_headers: true, headers: headers)
278
+ # csv_rows.each do |row|
279
+ # error_object = save_row_data(row)
280
+ # errors << error_object if error_object
281
+ # error_object.print_dot if error_object
282
+ # sum += 1
283
+ # end
284
+ # end
285
+ # end
286
+
287
+ # rows = CSV.new(File.open(csv_path,'r'), headers: true, header_converters: :symbol).lazy.select do |row|
288
+ # end
289
+
290
+ # binding.pry
291
+
292
+ # rows.each do |row|
293
+
294
+ # error_object = save_row_data(row)
295
+ # errors << error_object if error_object
296
+ # error_object.print_dot if error_object
297
+ # sum += 1
298
+ # end
299
+ end
300
+
301
+ end
302
+
303
+ end
@@ -0,0 +1,78 @@
1
+ module Kuppayam
2
+ module Validators
3
+
4
+ def generate_validation_options(attribute, options)
5
+ {a: 1}
6
+ reg_exp = /\A[a-zA-Z1-9\-\ \(\)\.+]*\z/i
7
+ options.reverse_merge!(
8
+ presence: true,
9
+ min_length: 3,
10
+ max_length: 256,
11
+ format: reg_exp,
12
+ uniqueness: false,
13
+ mandatory: false
14
+ )
15
+
16
+ if options.has_key?(:condition_method) && !options[:condition_method].blank?
17
+ condition_proc = proc {|obj| obj.send(options[:condition_method])}
18
+ elsif options.has_key?(:mandatory) && options[:mandatory] == false
19
+ condition_proc = proc {|obj| !obj.send(attribute).blank?}
20
+ else
21
+ condition_proc = nil
22
+ end
23
+
24
+ voptions = {
25
+ presence: options[:presence],
26
+ length: { minimum: options[:min_length], maximum: options[:max_length]},
27
+ format: {:with => options[:format]}
28
+ }
29
+ voptions.merge!(uniqueness: options[:uniqueness]) if options[:uniqueness]
30
+ voptions.merge!(if: condition_proc) if condition_proc
31
+
32
+ voptions
33
+ end
34
+
35
+ def validate_string(attribute, **options)
36
+ voptions = generate_validation_options(attribute, options)
37
+ validates attribute, **voptions
38
+ end
39
+
40
+ def validate_username(attribute, **options)
41
+ reg_exp = /\A[a-zA-Z0-9\_\.]*\z/
42
+ options.merge!(mandatory: true, min_length: 3, max_length: 128, format: reg_exp, :uniqueness => {:case_sensitive => false})
43
+ voptions = generate_validation_options(attribute, options)
44
+ validates attribute, **voptions
45
+ end
46
+
47
+ def validate_email(attribute, **options)
48
+ reg_exp = /\A(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6})\z/i
49
+ options.merge!(mandatory: true, format: reg_exp, :uniqueness => {:case_sensitive => false})
50
+ voptions = generate_validation_options(attribute, options)
51
+ validates attribute, **voptions
52
+ end
53
+
54
+ # format can be either :us or :indian
55
+ def validate_phone(attribute, **options)
56
+ options.reverse_merge!(phone_format: :india)
57
+ if options[:phone_format] == :us
58
+ reg_exp = /\A[0-9]{3}[-][0-9]{3}[-][0-9]{4}\z/
59
+ length = 12
60
+ else
61
+ reg_exp = /\A[0-9]{10}\z/
62
+ length = 10
63
+ end
64
+ options.merge!(format: reg_exp, min_length: length, max_length: length)
65
+ options.reverse_merge!(numericality: true, mandatory: true, uniqueness: true)
66
+ voptions = generate_validation_options(attribute, options)
67
+ validates attribute, **voptions
68
+ end
69
+
70
+ def validate_password(attribute, **options)
71
+ reg_exp = /\A(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9!@$#&*_\.,;:])/
72
+ options.merge!(mandatory: true, format: reg_exp, min_length: 7, max_length: 256)
73
+ voptions = generate_validation_options(attribute, options)
74
+ validates attribute, **voptions
75
+ end
76
+
77
+ end
78
+ end
@@ -23,6 +23,7 @@ en:
23
23
  updated: "%{item} has been updated successfully."
24
24
  deleted: "%{item} has been deleted successfully."
25
25
  removed: "%{item} has been removed successfully."
26
+ uploaded: "%{item} has been uploaded successfully."
26
27
  no_results_found: "No results found."
27
28
  state:
28
29
  changed: "%{item} has been %{new_state}."
@@ -1,6 +1,6 @@
1
1
  Rails.application.routes.draw do
2
2
 
3
- resources :images, controller: "kuppayam/images" do
3
+ resources :images, controller: "kuppayam/images" do
4
4
  member do
5
5
  put :crop
6
6
  end
@@ -8,6 +8,7 @@ class CreateImages < ActiveRecord::Migration[5.0]
8
8
  t.timestamps
9
9
  end
10
10
 
11
+ add_index(:images, :image_type)
11
12
  add_index(:images, [ :imageable_id, :imageable_type ])
12
13
  end
13
14
  end
@@ -1,4 +1,4 @@
1
- class CreateDocuments < ActiveRecord::Migration
1
+ class CreateDocuments < ActiveRecord::Migration[5.0]
2
2
  def change
3
3
  create_table :documents do |t|
4
4
  t.string :document
@@ -8,6 +8,7 @@ class CreateDocuments < ActiveRecord::Migration
8
8
  t.timestamps
9
9
  end
10
10
 
11
+ add_index(:documents, :document_type)
11
12
  add_index(:documents, [ :documentable_id, :documentable_type ])
12
13
  end
13
14
  end
@@ -1,9 +1,9 @@
1
- class CreateImportData < ActiveRecord::Migration
1
+ class CreateImportData < ActiveRecord::Migration[5.0]
2
2
  def change
3
3
  create_table :import_data do |t|
4
4
  t.integer :importable_id
5
5
  t.string :importable_type
6
- t.string :data_type
6
+ t.string :data_type # CSV, XLSX, XLS
7
7
  t.string :status, :null => false, :default=>"pending", :limit=>16
8
8
  t.timestamps
9
9
  end
@@ -145,7 +145,7 @@ module Kuppayam
145
145
  when :text, :email, :search, :password, :date, :time, :tel, :url, :month, :number
146
146
  text_field_tag(options[:param_name], object.send(field_name.to_s), **options[:html_options])
147
147
  when :textarea
148
- options[:html_options].merge!(style: "height: 140px;")
148
+ options[:html_options].reverse_merge!(style: "height: 140px;")
149
149
  text_area_tag(options[:param_name], object.send(field_name.to_s), **options[:html_options])
150
150
  when :file
151
151
  file_field_tag(options[:param_name], **options[:html_options])
@@ -6,6 +6,8 @@ module Kuppayam
6
6
  # <i class='fa fa-plus'></i>
7
7
  # theme_fa_icon('plus', 'lg')
8
8
  # <i class='fa fa-plus fa-lg'></i>
9
+
10
+ # TBR: To Be Removed
9
11
  def theme_fa_icon(icon_text, size="")
10
12
  size_class = %w{lg 2x 3x 4x 5x}.include?(size.strip) ? " fa-#{size.strip}" : ""
11
13
  "<i class='fa fa-#{icon_text}#{size_class}'></i>"
@@ -13,8 +15,10 @@ module Kuppayam
13
15
 
14
16
  # theme_button_text('New Project')
15
17
  # <span class='btn-text'> New Project</span>
18
+
19
+ # TBR: To Be Removed
16
20
  def theme_button_text(text)
17
- "<span class='btn-text'> #{text}</span>"
21
+ "<span class='btn-text hidden-sm hidden-xs'> #{text}</span>"
18
22
  end
19
23
 
20
24
  # theme_button is used to create buttons which has built in classes and icons
@@ -24,6 +28,8 @@ module Kuppayam
24
28
  # link_to raw("<i class='fa fa-plus mr-10'></i><span class='btn-text'> New Project</span>"), new_admin_project_path, :class=>"btn btn-primary pull-right ml-5", :remote=>true
25
29
  # And produces the following html
26
30
  # <a class="btn btn-primary pull-right ml-5" data-remote="true" href="/admin/projects/new"><i class="fa fa-plus mr-10"></i><span class="btn-text"> New Project</span></a>
31
+
32
+ # TBR: To Be Removed
27
33
  def theme_button(text, icon, url, options={})
28
34
  options.reverse_merge!(
29
35
  method: :get,
@@ -130,7 +136,7 @@ module Kuppayam
130
136
  # "No Results found"
131
137
  # </div>
132
138
  def theme_panel_message(message)
133
- content_tag(:div, class: "panel panel-default panel-message text-color-grey p-80 text-align-center", style: "height:200px;") do
139
+ content_tag(:div, class: "panel panel-default panel-message text-color-grey p-80 text-align-center", style: "height:200px;width:100%;") do
134
140
  raw(message)
135
141
  end
136
142
  end