marty 4.0.0.rc2 → 5.1.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 (72) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +7 -0
  3. data/.rubocop.yml +1 -0
  4. data/.rubocop_todo.yml +3 -16
  5. data/.ssh-docker/.keep +0 -0
  6. data/Dockerfile.dummy +3 -0
  7. data/Gemfile +19 -15
  8. data/app/components/marty/base_rule_view.rb +104 -10
  9. data/app/components/marty/base_rule_view/client/base_rule_view.js +24 -0
  10. data/app/components/marty/data_grid_user_view.rb +39 -0
  11. data/app/components/marty/data_grid_view.rb +68 -18
  12. data/app/components/marty/extras/layout.rb +1 -1
  13. data/app/components/marty/grid.rb +1 -1
  14. data/app/components/marty/grid/client/grid.js +29 -13
  15. data/app/components/marty/import_view.rb +3 -3
  16. data/app/components/marty/main_auth_app.rb +11 -1
  17. data/app/components/marty/report_form.rb +6 -6
  18. data/app/components/marty/script_form.rb +5 -5
  19. data/app/components/marty/script_tester.rb +2 -2
  20. data/app/components/marty/user_view.rb +3 -9
  21. data/app/models/marty/base_rule.rb +92 -32
  22. data/app/models/marty/data_grid.rb +92 -22
  23. data/app/models/marty/event.rb +2 -2
  24. data/app/models/marty/promise.rb +4 -4
  25. data/app/models/marty/role_type.rb +14 -1
  26. data/app/services/marty/data_grid_view/save_grid.rb +2 -2
  27. data/app/services/marty/promises/delorean/create.rb +2 -2
  28. data/app/services/marty/promises/ruby/create.rb +2 -2
  29. data/config/locales/en.yml +11 -2
  30. data/db/migrate/108_add_data_grid_perms.rb +16 -0
  31. data/db/migrate/508_add_not_to_data_grids_tables.rb +18 -0
  32. data/db/migrate/509_update_dg_plpgsql_v1_fns.rb +13 -0
  33. data/db/sql/query_grid_dir_v1.sql +16 -2
  34. data/docker-compose.dummy.yml +1 -0
  35. data/lib/marty/content_handler.rb +2 -2
  36. data/lib/marty/data_change.rb +1 -1
  37. data/lib/marty/data_conversion.rb +3 -4
  38. data/lib/marty/data_importer.rb +4 -4
  39. data/lib/marty/mcfly_model.rb +7 -10
  40. data/lib/marty/migrations.rb +1 -1
  41. data/lib/marty/monkey.rb +2 -2
  42. data/lib/marty/promise_job.rb +5 -5
  43. data/lib/marty/promise_proxy.rb +2 -2
  44. data/lib/marty/promise_ruby_job.rb +4 -4
  45. data/lib/marty/version.rb +1 -1
  46. data/make-app.mk +1 -1
  47. data/marty.gemspec +13 -18
  48. data/other/marty/diagnostic/aws/ec2_instance.rb +17 -2
  49. data/other/marty/diagnostic/aws/error.rb +8 -0
  50. data/other/marty/diagnostic/database.rb +2 -2
  51. data/other/marty/diagnostic/delayed_job_version.rb +0 -1
  52. data/spec/dummy/app/components/gemini/my_rule_view.rb +32 -6
  53. data/spec/dummy/app/models/gemini/fannie_bup.rb +13 -20
  54. data/spec/dummy/app/models/gemini/my_rule.rb +4 -0
  55. data/spec/dummy/app/models/gemini/xyz_rule.rb +3 -1
  56. data/spec/dummy/config/application.rb +1 -0
  57. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  58. data/spec/dummy/db/migrate/20190702115241_add_simple_guards_options_to_rules.rb +37 -0
  59. data/spec/features/data_grid_spec.rb +109 -47
  60. data/spec/features/reporting_spec.rb +4 -4
  61. data/spec/features/rule_spec.rb +62 -31
  62. data/spec/features/scripting_spec.rb +3 -3
  63. data/spec/features/user_view_spec.rb +17 -8
  64. data/spec/fixtures/csv/rule/MyRule.csv +4 -1
  65. data/spec/lib/data_importer_spec.rb +8 -8
  66. data/spec/lib/mcfly_model_spec.rb +6 -6
  67. data/spec/models/data_grid_spec.rb +139 -7
  68. data/spec/models/rule_spec.rb +116 -9
  69. data/spec/spec_helper.rb +2 -2
  70. data/spec/support/netzke.rb +4 -3
  71. metadata +55 -54
  72. data/Gemfile.lock +0 -289
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 2e88119aa409a4b6e0b108e44f821c9ae6f3c402bde7a0b5982aaac317f8c0c0
4
- data.tar.gz: f0e0a25f744a13ed98e647aa379c2421a54edc1dd8bf01e84262e4f952ce7ae2
2
+ SHA1:
3
+ metadata.gz: c1dd27f462d7a2a7c78919c8388b35464b2a09db
4
+ data.tar.gz: a82eb24eb59673ae6a7c9f4c48a690b06dd7f984
5
5
  SHA512:
6
- metadata.gz: cbfd7f8b4c3fcc8f7060f7913bd2330635517a52710acae731638d6190f05726174fddfca0447bc0400d06770e10c72dd371e24e0da4f9e2699495473041a3eb
7
- data.tar.gz: e17fa1789a98f3f67fa324b2b67e7bcc1a98c48101d62088a1c1196e9d148f9275b8c3a1134a03ed7b6022d7757cfc737b2598bfc071cfd22df215ce62876293
6
+ metadata.gz: 36f9986869878ae91ed80ebb0d4698609ed8cc19507103d4437c3469db2f3fa32aef09b21333ee62fe92cfa2e3eafa041088e2d248c75561d6f8d1aeea5c0493
7
+ data.tar.gz: a9d59ed17f912a53da36a6292c2c729ce6b4daad127e621170a845b2df93faaad4c509c0e0a4e1a587f6786446bde7356127b0f7fdf1130f7f3027f9836d1c38
data/.gitignore CHANGED
@@ -31,3 +31,10 @@ spec/dummy/.sass-cache
31
31
  # Files with command history for docker
32
32
  .bash_history.docker
33
33
  .pry_history.docker
34
+
35
+ # Keep empty for for ssh keys in docker
36
+ /.ssh-docker/*
37
+ !/.ssh-docker/.keep
38
+
39
+ # Ignore Gemfile.lock
40
+ Gemfile.lock
@@ -1,4 +1,5 @@
1
1
  inherit_from: .rubocop_todo.yml
2
+ require: rubocop-performance
2
3
 
3
4
  AllCops:
4
5
  TargetRubyVersion: 2.3.3
@@ -48,7 +48,7 @@ Layout/ExtraSpacing:
48
48
  # Cop supports --auto-correct.
49
49
  # Configuration parameters: EnforcedStyle, IndentationWidth.
50
50
  # SupportedStyles: special_inside_parentheses, consistent, align_braces
51
- Layout/IndentHash:
51
+ Layout/IndentFirstHashElement:
52
52
  Exclude:
53
53
  - 'app/components/marty/extras/layout.rb'
54
54
  - 'lib/marty/data_change.rb'
@@ -316,7 +316,7 @@ Metrics/BlockLength:
316
316
  # Offense count: 21
317
317
  # Configuration parameters: CountComments.
318
318
  Metrics/ClassLength:
319
- Max: 539
319
+ Max: 600
320
320
 
321
321
  # Offense count: 68
322
322
  Metrics/CyclomaticComplexity:
@@ -508,7 +508,7 @@ Performance/TimesMap:
508
508
 
509
509
  # Offense count: 1
510
510
  # Cop supports --auto-correct.
511
- Performance/UnneededSort:
511
+ Style/UnneededSort:
512
512
  Exclude:
513
513
  - 'app/models/marty/event.rb'
514
514
 
@@ -934,19 +934,6 @@ Style/Next:
934
934
  Style/NumericLiterals:
935
935
  MinDigits: 15
936
936
 
937
- # Offense count: 10
938
- # Cop supports --auto-correct.
939
- # Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
940
- # SupportedStyles: predicate, comparison
941
- Style/NumericPredicate:
942
- Exclude:
943
- - 'spec/**/*'
944
- - 'app/components/marty/main_auth_app.rb'
945
- - 'lib/marty/content_handler.rb'
946
- - 'lib/marty/data_change.rb'
947
- - 'lib/marty/data_importer.rb'
948
- - 'lib/marty/xl.rb'
949
-
950
937
  # Offense count: 42
951
938
  # Cop supports --auto-correct.
952
939
  Style/ParallelAssignment:
File without changes
@@ -24,6 +24,9 @@ RUN curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrom
24
24
  && sed -i 's|HERE/chrome\"|HERE/chrome\" --disable-setuid-sandbox|g' /opt/google/chrome/google-chrome \
25
25
  && rm google-chrome.deb
26
26
 
27
+ # Install additional tools
28
+ RUN apt-get install -qq -y --no-install-recommends netcat-openbsd vim
29
+
27
30
  RUN gem install bundler
28
31
 
29
32
  ENV BUNDLE_PATH /bundle_box/bundle
data/Gemfile CHANGED
@@ -5,33 +5,37 @@ source 'http://rubygems.org'
5
5
  # development dependencies will be added by default to the :development group.
6
6
  gemspec
7
7
 
8
- gem 'daemons'
9
- gem 'delayed_job_active_record'
10
- gem 'pg'
11
- gem 'rails', '~> 5.1.4'
12
- gem 'sqlite3'
8
+ group :default do
9
+ gem 'daemons'
10
+ gem 'delayed_job_active_record'
11
+ gem 'pg'
12
+ gem 'rails'
13
+ end
14
+
15
+ group :default, :cmit do
16
+ gem 'delorean_lang'
17
+ gem 'mcfly'
18
+ # gem 'delorean_lang', path: File.expand_path('../../delorean', __FILE__)
19
+ # gem 'mcfly', path: File.expand_path('../../mcfly', __FILE__)
20
+ end
13
21
 
14
22
  group :development, :test do
15
- gem 'capybara', '~> 2.18.0'
23
+ gem 'capybara'
16
24
  gem 'connection_pool'
17
25
  gem 'database_cleaner'
26
+ gem 'fuubar', require: false
27
+ gem 'netzke', '6.5.0.0'
18
28
  gem 'pry-byebug'
19
29
  gem 'pry-rails'
30
+ gem 'puma'
20
31
  gem 'rails-controller-testing'
21
32
  gem 'rspec-instafail', require: false
22
33
  gem 'rspec-rails'
23
34
  gem 'rspec-retry'
24
35
  gem 'rubocop', require: false
36
+ gem 'rubocop-performance', require: false
37
+ gem 'rubocop-rails', require: false
25
38
  gem 'selenium-webdriver'
26
39
  gem 'timecop'
27
40
  gem 'webdrivers'
28
-
29
- # gem 'mcfly', path: File.expand_path('../../mcfly', __FILE__)
30
- gem 'mcfly'
31
- gem 'netzke', '6.5.0.0'
32
-
33
- # gem 'delorean_lang', path: File.expand_path('../../delorean', __FILE__)
34
-
35
- # gem 'marty_rspec', path: File.expand_path('../../marty_rspec', __FILE__)
36
- gem 'marty_rspec'
37
41
  end
@@ -22,16 +22,25 @@ class Marty::BaseRuleView < Marty::McflyGridPanel
22
22
  c.model = self.class.klass
23
23
  c.title = I18n.t('rule')
24
24
  c.attributes = self.class.base_fields +
25
- klass.guard_info.
26
- sort_by { |_, h| h[:order] || 0 }.
27
- reject { |_, h| h[:hidden] }.
28
- map { |name, _| name.to_sym } + self.class.computed_fields
25
+ guard_info_attributes + self.class.computed_fields
29
26
  c.store_config.merge!(sorters: [{ property: :name, direction: 'ASC' }])
30
27
  c.editing = :in_form
31
28
  c.paging = :pagination
32
29
  c.multi_select = false
33
30
  end
34
31
 
32
+ def guard_info_attributes
33
+ res = klass.guard_info.
34
+ sort_by { |_, h| h[:order] || 0 }.
35
+ reject { |_, h| h[:hidden] }.
36
+ map do |name, opts|
37
+ next name.to_sym unless opts.fetch(:allow_not, true)
38
+
39
+ [name.to_sym, "#{name}_not".to_sym]
40
+ end
41
+ res.flatten
42
+ end
43
+
35
44
  def default_bbar
36
45
  super + [:dup_in_form]
37
46
  end
@@ -222,7 +231,11 @@ class Marty::BaseRuleView < Marty::McflyGridPanel
222
231
  end
223
232
 
224
233
  def form_items_guards
225
- klass.guard_info.reject { |_, h| h[:hidden] }.keys.map(&:to_sym)
234
+ klass.guard_info.reject { |_, h| h[:hidden] }.map do |field, opts|
235
+ next { field: field.to_sym } unless opts.fetch(:allow_not, true)
236
+
237
+ { field: field.to_sym, not_field: "#{field.to_sym}_not".to_sym }
238
+ end
226
239
  end
227
240
 
228
241
  def form_items_grids
@@ -246,17 +259,56 @@ class Marty::BaseRuleView < Marty::McflyGridPanel
246
259
  height: 225)]
247
260
  end
248
261
 
262
+ def default_form_items_guards
263
+ with_not_fields = form_items_guards.any? { |h| h.key?(:not_field) }
264
+
265
+ guards = form_items_guards.map do |h|
266
+ if with_not_fields
267
+ hbox(
268
+ vbox(h.fetch(:field), width: '78%', border: false),
269
+ vbox(width: '2%', border: false),
270
+ vbox(h.fetch(:not_field, nil), width: '20%', border: false),
271
+ width: '100%',
272
+ border: false
273
+ )
274
+ else
275
+ hbox(
276
+ vbox(h.fetch(:field), width: '100%', border: false),
277
+ width: '100%',
278
+ border: false
279
+ )
280
+ end
281
+ end
282
+ end
283
+
249
284
  def default_form_items
250
285
  [
251
286
  hbox(
252
- vbox(*form_items_attrs +
253
- form_items_guards,
254
- border: false,
255
- width: '40%',
287
+ vbox(
288
+ hbox(
289
+ vbox(
290
+ *form_items_attrs,
291
+ width: '100%',
292
+ border: false
293
+ ),
294
+ width: '100%',
295
+ border: false
296
+ ),
297
+ hbox(
298
+ vbox(
299
+ *default_form_items_guards,
300
+ width: '100%',
301
+ border: false
256
302
  ),
303
+ width: '100%',
304
+ border: false
305
+ ),
306
+ width: '40%',
307
+ border: false
308
+ ),
257
309
  vbox(width: '2%', border: false),
258
310
  vbox(
259
- width: '55%', border: false),
311
+ width: '5%', border: false),
260
312
  height: '40%',
261
313
  border: false,
262
314
  ),
@@ -310,10 +362,42 @@ class Marty::BaseRuleView < Marty::McflyGridPanel
310
362
  else
311
363
  c.getter = range_getter(namestr, meth)
312
364
  c.setter = range_setter(namestr, meth)
365
+
313
366
  c.filterable = false
314
367
  end
368
+
369
+ c.column_config = {
370
+ renderer: 'simpleGuardColumnRenderer'
371
+ }
315
372
  c.sorting_scope = get_json_sorter(meth, namestr)
316
373
  end
374
+
375
+ # Checkbox and hidden column for "NOT" option for simpleguards
376
+ attribute "#{name}_not" do |c|
377
+ c.width = 30
378
+ c.label = 'Not'
379
+ c.type = :boolean
380
+ c.filterable = false
381
+ c.column_config = { hidden: true }
382
+
383
+ c.field_config = {
384
+ label_align: 'right',
385
+ max_width: 100,
386
+ label_pad: 2,
387
+ label_width: 30
388
+ }
389
+ c.getter = lambda do |record|
390
+ record.simple_guards_options.dig(name.to_s, 'not')
391
+ end
392
+
393
+ c.setter = lambda do |record, value|
394
+ options = record.simple_guards_options.fetch(name.to_s, {})
395
+ new_options = options.merge('not' => value)
396
+ record.simple_guards_options = record.simple_guards_options.merge(
397
+ name.to_s => new_options
398
+ )
399
+ end
400
+ end
317
401
  end
318
402
 
319
403
  attribute :start_dt do |c|
@@ -347,4 +431,14 @@ class Marty::BaseRuleView < Marty::McflyGridPanel
347
431
  end
348
432
  end
349
433
  end
434
+
435
+ client_class do |c|
436
+ c.myy_renderer = l(<<-JS)
437
+ function(value){
438
+ console.log(arguments)
439
+
440
+ return value ? "*" + value + "*" : "";
441
+ }
442
+ JS
443
+ end
350
444
  end
@@ -0,0 +1,24 @@
1
+ {
2
+ simpleGuardColumnRenderer: function(value, cell, obj) {
3
+ if (value === undefined || value === null) {
4
+ return value
5
+ }
6
+
7
+ if (!(cell && cell.column && cell.column.config && cell.column.config.name)) {
8
+ return value;
9
+ }
10
+
11
+ if (!(obj && obj.data)) {
12
+ return value;
13
+ }
14
+
15
+ column_name = cell.column.config.name;
16
+ with_not = obj.data[`${column_name}_not`];
17
+
18
+ if (with_not) {
19
+ return `NOT (${value})`
20
+ }
21
+
22
+ return value;
23
+ }
24
+ }
@@ -0,0 +1,39 @@
1
+ module Marty
2
+ class DataGridUserView < DataGridView
3
+ has_marty_permissions read: [:data_grid_editor, :admin, :dev]
4
+
5
+ def configure(c)
6
+ super
7
+
8
+ c.attributes =
9
+ [
10
+ :name,
11
+ :created_dt,
12
+ ]
13
+ c.editing = :inline
14
+ end
15
+
16
+ def default_bbar
17
+ [:edit_grid]
18
+ end
19
+
20
+ def get_records(params)
21
+ cur_perms = Mcfly.whodunnit.roles.map(&:to_sym)
22
+ model.where("permissions->'view' ?| ARRAY[:roles] OR "\
23
+ "permissions->'edit_data' ?| ARRAY[:roles] OR "\
24
+ "permissions->'edit_all' ?| ARRAY[:roles]",
25
+ roles: cur_perms).scoping do
26
+ super
27
+ end
28
+ end
29
+
30
+ def self.get_edit_permission(permissions)
31
+ cur_perms = current_user_roles.map(&:to_s)
32
+ ['edit_all', 'edit_data', 'view'].detect do |p|
33
+ permissions[p] - cur_perms != permissions[p]
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ DataGridUserView = Marty::DataGridUserView
@@ -98,6 +98,9 @@ module Marty; class DataGridView < McflyGridPanel
98
98
  :lenient,
99
99
  :data_type,
100
100
  :constraint,
101
+ :perm_view,
102
+ :perm_edit_data,
103
+ :perm_edit_all,
101
104
  :created_dt,
102
105
  ]
103
106
 
@@ -107,6 +110,19 @@ module Marty; class DataGridView < McflyGridPanel
107
110
  c.multi_select = false
108
111
  end
109
112
 
113
+ def set_perms(dg, data)
114
+ permstrs = %w[perm_view perm_edit_data perm_edit_all]
115
+ view, edit_data, edit_all = data.values_at(*permstrs).map do |plist|
116
+ Marty::RoleType.from_nice_names(plist)
117
+ end
118
+ dg.permissions = {
119
+ view: view.present? ? view : [],
120
+ edit_data: edit_data.present? ? edit_data : [],
121
+ edit_all: edit_all.present? ? edit_all : [],
122
+ }
123
+ dg.save!
124
+ end
125
+
110
126
  endpoint :add_window__add_form__submit do |params|
111
127
  data = ActiveSupport::JSON.decode(params[:data])
112
128
 
@@ -114,11 +130,12 @@ module Marty; class DataGridView < McflyGridPanel
114
130
  !config[:permissions][:create]
115
131
 
116
132
  begin
117
- DataGrid.create_from_import(data['name'], data['export'])
133
+ dg = DataGrid.create_from_import(data['name'], data['export'])
134
+ set_perms(dg, data)
118
135
  client.success = true
119
136
  client.netzke_on_submit_success
120
- rescue StandardError => exc
121
- client.netzke_notify(exc.to_s)
137
+ rescue StandardError => e
138
+ client.netzke_notify(e.to_s)
122
139
  end
123
140
  end
124
141
 
@@ -129,10 +146,11 @@ module Marty; class DataGridView < McflyGridPanel
129
146
 
130
147
  begin
131
148
  dg.update_from_import(data['name'], data['export'])
149
+ set_perms(dg, data)
132
150
  client.success = true
133
151
  client.netzke_on_submit_success
134
- rescue StandardError => exc
135
- client.netzke_notify(exc.to_s)
152
+ rescue StandardError => e
153
+ client.netzke_notify(e.to_s)
136
154
  end
137
155
  end
138
156
 
@@ -168,14 +186,8 @@ module Marty; class DataGridView < McflyGridPanel
168
186
  client.netzke_client_show_grid maxcount, res, 'Data Grid'
169
187
  end
170
188
 
171
- # placeholders for grid editing permission logic.
172
- # for now, this allows the rspec to control the permission
173
- def self.get_edit_edit_permission
174
- Marty::Config['grid_edit_edit_perm'] || 'edit_all'
175
- end
176
-
177
- def self.get_edit_save_permission
178
- Marty::Config['grid_edit_save_perm'] || 'edit_all'
189
+ def self.get_edit_permission(_permissions)
190
+ 'edit_all'
179
191
  end
180
192
 
181
193
  endpoint :edit_grid do |params|
@@ -193,9 +205,21 @@ module Marty; class DataGridView < McflyGridPanel
193
205
  vdim = md.map { |m| m['dir'] == 'v' && m['attr'] }.select { |v| v }
194
206
  hdim_en = hdim.map { |d| I18n.t('attributes.' + d, default: d) }
195
207
  vdim_en = vdim.map { |d| I18n.t('attributes.' + d, default: d) }
196
- name = "Editing Data Grid '#{dg.name}'"
197
- permission = Marty::DataGridView.get_edit_edit_permission
198
- client.edit_grid(record_id, hdim_en, vdim_en, res, name, permission)
208
+ perm = self.class.get_edit_permission(dg.permissions)
209
+ # should never happen
210
+ return client.netzke_notify('No permission to edit/view grid.') unless perm
211
+
212
+ doing = case perm
213
+ when 'view'
214
+ 'Viewing'
215
+ when 'edit_all'
216
+ 'Editing (all)'
217
+ when 'edit_data'
218
+ 'Editing (data only)'
219
+ end
220
+ name = "#{doing} Data Grid '#{dg.name}'"
221
+
222
+ client.edit_grid(record_id, hdim_en, vdim_en, res, name, perm)
199
223
  end
200
224
 
201
225
  endpoint :save_grid do |params|
@@ -213,10 +237,36 @@ module Marty; class DataGridView < McflyGridPanel
213
237
  def default_form_items
214
238
  [
215
239
  :name,
240
+ :perm_view, :perm_edit_data, :perm_edit_all,
216
241
  textarea_field(:export, height: 300, hide_label: true),
217
242
  ]
218
243
  end
219
244
 
245
+ ['view', 'edit_data', 'edit_all'].each do |p|
246
+ s = ('perm_' + p).to_s
247
+ attribute s do |c|
248
+ c.width = 100
249
+ c.flex = 1
250
+ c.label = I18n.t("data_grid_view_perms.#{s}")
251
+ c.type = :string
252
+ c.getter = lambda do |r|
253
+ Marty::RoleType.to_nice_names(r.permissions[p].sort)
254
+ end
255
+ store = Marty::RoleType.to_nice_names(::Marty::RoleType.get_all.sort.map)
256
+
257
+ # edit does not work without this dummy setter
258
+ c.setter = ->(r, v) {}
259
+
260
+ c.editor_config = {
261
+ multi_select: true,
262
+ empty_text: I18n.t('user_grid.select_roles'),
263
+ store: store,
264
+ type: :string,
265
+ xtype: :combo,
266
+ }
267
+ end
268
+ end
269
+
220
270
  component :edit_window do |c|
221
271
  super(c)
222
272
  c.width = 700
@@ -228,11 +278,11 @@ module Marty; class DataGridView < McflyGridPanel
228
278
  end
229
279
 
230
280
  attribute :name do |c|
231
- c.width = 120
281
+ c.width = 400
232
282
  end
233
283
 
234
284
  attribute :constraint do |c|
235
- c.width = 100
285
+ c.width = 150
236
286
  end
237
287
 
238
288
  attribute :hcols do |c|