marty 1.0.20 → 1.0.22
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/app/components/marty/data_grid_view.rb +203 -0
- data/app/components/marty/extras/layout.rb +149 -82
- data/app/components/marty/main_auth_app.rb +36 -26
- data/app/components/marty/user_view.rb +42 -41
- data/app/controllers/marty/diagnostic_controller.rb +37 -1
- data/app/models/marty/data_grid.rb +20 -20
- data/config/locales/en.yml +5 -0
- data/lib/marty/version.rb +1 -1
- data/spec/controllers/diagnostic_controller_spec.rb +32 -0
- data/spec/models/data_grid_spec.rb +9 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86d8dcf6f031cb37849a2835413f01577fe15309
|
4
|
+
data.tar.gz: 3230c2099f30abb9f60c6d17d1b7da528e1b928c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6ffb9f4a6e963960f7d22254444c937431f4c185a1be67b6161db0b1d50fabfc857cf39cef9c6100db74d622ea406aed702b2d37863ef5c9af6c005d60e1057
|
7
|
+
data.tar.gz: 4a0f2d03b75bb07f97f0fb38625a2f3b821a71df0286d27eeae4333965a8d21d6fd3bbfb819f8d47e3d2b6d771f7e33362c42e588b46d0e86f85748c3cc4e3aa
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module Marty; class DataGridView < McflyGridPanel
|
2
|
+
has_marty_permissions create: [:admin, :dev],
|
3
|
+
read: :any,
|
4
|
+
update: [:admin, :dev],
|
5
|
+
delete: [:admin, :dev]
|
6
|
+
|
7
|
+
include Extras::Layout
|
8
|
+
|
9
|
+
def self.show_grid_js(options={})
|
10
|
+
dg = options[:data_grid] || 'data_grid'
|
11
|
+
title_str = options[:title_str] || 'Data Grid'
|
12
|
+
|
13
|
+
javascript = l(<<-JS)
|
14
|
+
function() {
|
15
|
+
var sel = this.getSelectionModel().selected.first();
|
16
|
+
var record_id = sel && sel.getId();
|
17
|
+
this.server.showGrid({record_id: record_id,
|
18
|
+
data_grid: "#{dg}",
|
19
|
+
title_str: "#{title_str}"});
|
20
|
+
}
|
21
|
+
JS
|
22
|
+
javascript
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.client_show_grid_js
|
26
|
+
javascript = l(<<-JS)
|
27
|
+
function(count, data, title_str) {
|
28
|
+
var columns = [];
|
29
|
+
var fields = [];
|
30
|
+
|
31
|
+
for (var i=0; i<count; i++) {
|
32
|
+
fields.push("a" + i);
|
33
|
+
columns.push({dataIndex: "a" + i, text: i, flex: 1});
|
34
|
+
}
|
35
|
+
|
36
|
+
Ext.create('Ext.Window', {
|
37
|
+
height: "80%",
|
38
|
+
width: "80%",
|
39
|
+
x: 0,
|
40
|
+
y: 0,
|
41
|
+
autoWidth: true,
|
42
|
+
modal: true,
|
43
|
+
autoScroll: true,
|
44
|
+
title: title_str,
|
45
|
+
items: {
|
46
|
+
xtype: 'grid',
|
47
|
+
border: false,
|
48
|
+
hideHeaders: false,
|
49
|
+
columns: columns,
|
50
|
+
store: Ext.create('Ext.data.ArrayStore', {
|
51
|
+
fields: fields,
|
52
|
+
data: data,
|
53
|
+
})
|
54
|
+
},
|
55
|
+
}).show();
|
56
|
+
}
|
57
|
+
JS
|
58
|
+
javascript
|
59
|
+
end
|
60
|
+
|
61
|
+
client_class do |c|
|
62
|
+
c.netzke_show_grid = DataGridView.show_grid_js
|
63
|
+
c.netzke_client_show_grid = DataGridView.client_show_grid_js
|
64
|
+
end
|
65
|
+
|
66
|
+
def configure(c)
|
67
|
+
super
|
68
|
+
|
69
|
+
c.title = I18n.t('data_grid')
|
70
|
+
c.model = "Marty::DataGrid"
|
71
|
+
c.attributes =
|
72
|
+
[
|
73
|
+
:name,
|
74
|
+
:vcols,
|
75
|
+
:hcols,
|
76
|
+
:lenient,
|
77
|
+
:data_type,
|
78
|
+
:created_dt,
|
79
|
+
]
|
80
|
+
|
81
|
+
c.store_config.merge!({sorters: [{property: :name, direction: 'ASC'}]})
|
82
|
+
c.editing = :in_form
|
83
|
+
c.paging = :pagination
|
84
|
+
c.multi_select = false
|
85
|
+
end
|
86
|
+
|
87
|
+
endpoint :add_window__add_form__submit do |params|
|
88
|
+
data = ActiveSupport::JSON.decode(params[:data])
|
89
|
+
|
90
|
+
return client.netzke_notify("Permission Denied") if
|
91
|
+
!config[:permissions][:create]
|
92
|
+
|
93
|
+
begin
|
94
|
+
DataGrid.create_from_import(data["name"], data["export"])
|
95
|
+
client.success = true
|
96
|
+
client.netzke_on_submit_success
|
97
|
+
rescue => exc
|
98
|
+
client.netzke_notify(exc.to_s)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
endpoint :edit_window__edit_form__submit do |params|
|
103
|
+
data = ActiveSupport::JSON.decode(params[:data])
|
104
|
+
|
105
|
+
dg = DataGrid.find_by_id(data["id"])
|
106
|
+
|
107
|
+
begin
|
108
|
+
dg.update_from_import(data["name"], data["export"])
|
109
|
+
client.success = true
|
110
|
+
client.netzke_on_submit_success
|
111
|
+
rescue => exc
|
112
|
+
client.netzke_notify(exc.to_s)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
action :show_grid do |a|
|
117
|
+
a.text = "Show Grid"
|
118
|
+
a.icon = :application_view_detail
|
119
|
+
a.handler = :netzke_show_grid
|
120
|
+
end
|
121
|
+
|
122
|
+
endpoint :show_grid do |params|
|
123
|
+
record_id = params[:record_id]
|
124
|
+
|
125
|
+
dg = DataGrid.find_by_id(record_id)
|
126
|
+
|
127
|
+
return client.netzke_notify("No data grid.") unless dg
|
128
|
+
|
129
|
+
meta_rows_raw, h_key_rows, data_rows = dg.export_array
|
130
|
+
meta_rows = meta_rows_raw.map do |row|
|
131
|
+
# need to escape for HTML, otherwise characters such as >, <,
|
132
|
+
# etc. not displayed properly.
|
133
|
+
row.map { |field| CGI::escapeHTML(field) }
|
134
|
+
end
|
135
|
+
res = meta_rows + [[]] + h_key_rows + data_rows
|
136
|
+
|
137
|
+
maxcount = res.map(&:length).max
|
138
|
+
|
139
|
+
client.netzke_client_show_grid maxcount, res, 'Data Grid'
|
140
|
+
end
|
141
|
+
|
142
|
+
def default_bbar
|
143
|
+
[:show_grid] + super
|
144
|
+
end
|
145
|
+
|
146
|
+
def default_context_menu
|
147
|
+
[]
|
148
|
+
end
|
149
|
+
|
150
|
+
def default_form_items
|
151
|
+
[
|
152
|
+
:name,
|
153
|
+
textarea_field(:export, height: 300, hide_label: true),
|
154
|
+
]
|
155
|
+
end
|
156
|
+
|
157
|
+
component :edit_window do |c|
|
158
|
+
super(c)
|
159
|
+
c.width = 700
|
160
|
+
end
|
161
|
+
|
162
|
+
component :add_window do |c|
|
163
|
+
super(c)
|
164
|
+
c.width = 700
|
165
|
+
end
|
166
|
+
|
167
|
+
attribute :name do |c|
|
168
|
+
c.width = 120
|
169
|
+
end
|
170
|
+
|
171
|
+
attribute :hcols do |c|
|
172
|
+
c.label = "Horizontal Attrs"
|
173
|
+
c.width = 200
|
174
|
+
c.getter = lambda { |r|
|
175
|
+
r.dir_infos("h").map {|inf| inf["attr"]}.join(', ')
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
attribute :vcols do |c|
|
180
|
+
c.label = "Vertical Attrs"
|
181
|
+
c.width = 200
|
182
|
+
c.getter = lambda { |r|
|
183
|
+
r.dir_infos("v").map {|inf| inf["attr"]}.join(', ')
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
attribute :lenient do |c|
|
188
|
+
c.width = 75
|
189
|
+
end
|
190
|
+
|
191
|
+
attribute :data_type do |c|
|
192
|
+
c.label = "Data Type"
|
193
|
+
c.width = 200
|
194
|
+
end
|
195
|
+
|
196
|
+
attribute :created_dt do |c|
|
197
|
+
c.label = I18n.t('updated_at')
|
198
|
+
c.format = "Y-m-d H:i"
|
199
|
+
c.read_only = true
|
200
|
+
end
|
201
|
+
end; end
|
202
|
+
|
203
|
+
DataGridView = Marty::DataGridView
|
@@ -1,84 +1,151 @@
|
|
1
|
-
module Marty
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
1
|
+
module Marty; module Extras
|
2
|
+
module Layout
|
3
|
+
def hbox(*args)
|
4
|
+
params = args.pop
|
5
|
+
params.merge(layout: { type: :hbox, align: :stretch },
|
6
|
+
items: args,
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
def vbox(*args)
|
11
|
+
params = args.pop
|
12
|
+
params.merge(layout: { type: :vbox, align: :stretch },
|
13
|
+
items: args,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def fieldset(title, *args)
|
18
|
+
params = args.pop
|
19
|
+
params.merge(items: args,
|
20
|
+
xtype: 'fieldset',
|
21
|
+
defaults: { anchor: '100%' },
|
22
|
+
title: title,
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def dispfield(params={})
|
27
|
+
{
|
28
|
+
attr_type: :displayfield,
|
29
|
+
hide_label: !params[:field_label],
|
30
|
+
read_only: true,
|
31
|
+
}.merge(params)
|
32
|
+
end
|
33
|
+
|
34
|
+
def vspacer(params={})
|
35
|
+
vbox({flex: 1, border: false}.merge(params))
|
36
|
+
end
|
37
|
+
|
38
|
+
def hspacer(params={})
|
39
|
+
hbox({flex: 1, border: false}.merge(params))
|
40
|
+
end
|
41
|
+
|
42
|
+
def textarea_field(name, options={})
|
43
|
+
{
|
44
|
+
name: name,
|
45
|
+
width: "100%",
|
46
|
+
height: 150,
|
47
|
+
xtype: :textareafield,
|
48
|
+
auto_scroll: true,
|
49
|
+
spellcheck: false,
|
50
|
+
field_style: {
|
51
|
+
font_family: 'courier new',
|
52
|
+
font_size: '12px'
|
53
|
+
},
|
54
|
+
} + options
|
55
|
+
end
|
56
|
+
|
57
|
+
######################################################################
|
58
|
+
# PG ENUM field handling
|
59
|
+
|
60
|
+
def enum_column(c, klass)
|
61
|
+
editor_config = {
|
62
|
+
trigger_action: :all,
|
63
|
+
xtype: :combo,
|
64
|
+
|
65
|
+
# hacky: extjs has issues with forceSelection true and clearing combos
|
66
|
+
store: klass::VALUES + ['---'],
|
67
|
+
forceSelection: true,
|
68
|
+
}
|
69
|
+
c.merge!(
|
70
|
+
column_config: { editor: editor_config },
|
71
|
+
field_config: editor_config,
|
72
|
+
type: :string,
|
73
|
+
setter: enum_setter(c.name),
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def enum_setter(name)
|
78
|
+
lambda {|r, v| r.send("#{name}=", v == '---' || v.empty? ? nil : v)}
|
79
|
+
end
|
80
|
+
|
81
|
+
######################################################################
|
82
|
+
# employ lots of hakery to implement NULLable boolean field in
|
83
|
+
# Netzke 8.x.
|
84
|
+
|
85
|
+
BOOL_MAP = {
|
86
|
+
nil => "---",
|
87
|
+
true => "True",
|
88
|
+
false => "False",
|
89
|
+
}
|
90
|
+
|
91
|
+
MAP_BOOL = {
|
92
|
+
"---" => nil,
|
93
|
+
"" => nil,
|
94
|
+
"True" => true,
|
95
|
+
"False" => false,
|
96
|
+
}
|
97
|
+
|
98
|
+
def bool_getter(name)
|
99
|
+
lambda {|r| BOOL_MAP[r.send(name)]}
|
100
|
+
end
|
101
|
+
|
102
|
+
def bool_setter(name)
|
103
|
+
lambda {|r, v| r.send("#{name}=", MAP_BOOL[v])}
|
104
|
+
end
|
105
|
+
|
106
|
+
def nullable_bool_column(name)
|
107
|
+
editor_config = {
|
108
|
+
trigger_action: :all,
|
109
|
+
xtype: :combo,
|
110
|
+
store: ["True", "False", "---"],
|
111
|
+
}
|
112
|
+
{
|
113
|
+
column_config: { editor: editor_config },
|
114
|
+
field_config: editor_config,
|
115
|
+
type: :string,
|
116
|
+
getter: bool_getter(name),
|
117
|
+
setter: bool_setter(name),
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
######################################################################
|
122
|
+
# make sure to validate range vals on the model (e.g. see rule.rb)
|
123
|
+
|
124
|
+
def range_getter(name)
|
125
|
+
lambda { |r|
|
126
|
+
Marty::Util.pg_range_to_human(r.send(name))
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def range_setter(name)
|
131
|
+
lambda do |r, v|
|
132
|
+
r.send("#{name}=", v && (Marty::Util.human_to_pg_range(v) rescue v))
|
82
133
|
end
|
83
134
|
end
|
84
|
-
|
135
|
+
|
136
|
+
def range_field(name)
|
137
|
+
{
|
138
|
+
name: name,
|
139
|
+
getter: range_getter(name),
|
140
|
+
setter: range_setter(name),
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def range_column(c, name)
|
145
|
+
c.getter = range_getter(name)
|
146
|
+
c.setter = range_setter(name)
|
147
|
+
c.width = 80
|
148
|
+
c.align = 'right'
|
149
|
+
end
|
150
|
+
|
151
|
+
end; end; end
|
@@ -8,6 +8,7 @@ require 'marty/event_view'
|
|
8
8
|
require 'marty/promise_view'
|
9
9
|
require 'marty/api_auth_view'
|
10
10
|
require 'marty/config_view'
|
11
|
+
require 'marty/data_grid_view'
|
11
12
|
|
12
13
|
class Marty::MainAuthApp < Marty::AuthApp
|
13
14
|
extend ::Marty::Permissions
|
@@ -39,10 +40,10 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
39
40
|
icon: icon_hack(:time),
|
40
41
|
style: (warped ? "background-color: lightGrey;" : ""),
|
41
42
|
menu: [
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
:new_posting,
|
44
|
+
:select_posting,
|
45
|
+
:select_now,
|
46
|
+
],
|
46
47
|
}
|
47
48
|
end
|
48
49
|
|
@@ -52,14 +53,14 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
52
53
|
icon: icon_hack(:wrench),
|
53
54
|
style: "",
|
54
55
|
menu: [
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
:import_type_view,
|
57
|
+
:user_view,
|
58
|
+
:config_view,
|
59
|
+
:api_auth_view,
|
60
|
+
:event_view,
|
61
|
+
:reload_scripts,
|
62
|
+
:load_seed,
|
63
|
+
] + background_jobs_menu
|
63
64
|
}
|
64
65
|
end
|
65
66
|
|
@@ -68,25 +69,26 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
68
69
|
text: I18n.t("applications"),
|
69
70
|
icon: icon_hack(:application_cascade),
|
70
71
|
menu: [
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
:data_grid_view,
|
73
|
+
:reporting,
|
74
|
+
:scripting,
|
75
|
+
:promise_view,
|
76
|
+
],
|
75
77
|
}
|
76
78
|
end
|
77
79
|
|
78
80
|
def background_jobs_menu
|
79
81
|
[
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
82
|
+
{
|
83
|
+
text: 'Background Jobs',
|
84
|
+
icon: icon_hack(:clock),
|
85
|
+
disabled: !self.class.has_admin_perm?,
|
86
|
+
menu: [
|
87
|
+
:bg_status,
|
88
|
+
:bg_stop,
|
89
|
+
:bg_restart,
|
90
|
+
]
|
91
|
+
},
|
90
92
|
]
|
91
93
|
end
|
92
94
|
|
@@ -191,6 +193,13 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
191
193
|
a.disabled = !self.class.has_admin_perm?
|
192
194
|
end
|
193
195
|
|
196
|
+
action :data_grid_view do |a|
|
197
|
+
a.text = I18n.t("data_grid_view", default: "Data Grids")
|
198
|
+
a.handler = :netzke_load_component_by_action
|
199
|
+
a.icon = :table_multiple
|
200
|
+
a.disabled = !self.class.has_any_perm?
|
201
|
+
end
|
202
|
+
|
194
203
|
action :reload_scripts do |a|
|
195
204
|
a.text = 'Reload Scripts'
|
196
205
|
a.tooltip = 'Reload and tag Delorean scripts'
|
@@ -430,6 +439,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
430
439
|
component :user_view
|
431
440
|
component :event_view
|
432
441
|
component :config_view
|
442
|
+
component :data_grid_view
|
433
443
|
component :api_auth_view do |c|
|
434
444
|
c.disabled = Marty::Util.warped?
|
435
445
|
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
class
|
2
|
-
has_marty_permissions
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
delete: [:admin, :user_manager]
|
1
|
+
module Marty; class UserView < Marty::Grid
|
2
|
+
has_marty_permissions create: [:admin, :user_manager],
|
3
|
+
read: :any,
|
4
|
+
update: [:admin, :user_manager],
|
5
|
+
delete: [:admin, :user_manager]
|
7
6
|
|
8
7
|
# list of columns to be displayed in the grid view
|
9
8
|
def self.user_columns
|
@@ -19,15 +18,15 @@ class Marty::UserView < Marty::Grid
|
|
19
18
|
def configure(c)
|
20
19
|
super
|
21
20
|
|
22
|
-
c.
|
23
|
-
c.
|
24
|
-
c.
|
25
|
-
c.
|
26
|
-
c.
|
27
|
-
c.
|
28
|
-
c.store_config.merge!(
|
29
|
-
|
30
|
-
|
21
|
+
c.attributes ||= self.class.user_columns
|
22
|
+
c.title ||= I18n.t('users', default: "Users")
|
23
|
+
c.model = "Marty::User"
|
24
|
+
c.editing = :in_form
|
25
|
+
c.paging = :pagination
|
26
|
+
c.multi_select = false
|
27
|
+
c.store_config.merge!(sorters: [{property: :login,
|
28
|
+
direction: 'ASC',
|
29
|
+
}]) if c.attributes.include?(:login)
|
31
30
|
c.scope = ->(arel) { arel.includes(:roles) }
|
32
31
|
end
|
33
32
|
|
@@ -40,14 +39,14 @@ class Marty::UserView < Marty::Grid
|
|
40
39
|
end
|
41
40
|
|
42
41
|
# set new roles
|
43
|
-
user.roles =
|
42
|
+
user.roles = Role.select {
|
44
43
|
|r| roles.include? I18n.t("roles.#{r.name}")
|
45
44
|
}
|
46
45
|
end
|
47
46
|
|
48
47
|
def self.create_edit_user(data)
|
49
48
|
# Creates initial place-holder user object and validate
|
50
|
-
user = data["id"].nil? ?
|
49
|
+
user = data["id"].nil? ? User.new : User.find(data["id"])
|
51
50
|
|
52
51
|
self.user_columns.each {
|
53
52
|
|c| user.send("#{c}=", data[c.to_s]) unless c == :roles
|
@@ -101,19 +100,19 @@ class Marty::UserView < Marty::Grid
|
|
101
100
|
|
102
101
|
action :add do |a|
|
103
102
|
super(a)
|
104
|
-
a.text
|
105
|
-
a.tooltip
|
106
|
-
a.icon
|
103
|
+
a.text = I18n.t("user_grid.new")
|
104
|
+
a.tooltip = I18n.t("user_grid.new")
|
105
|
+
a.icon = :user_add
|
107
106
|
end
|
108
107
|
|
109
108
|
action :edit do |a|
|
110
109
|
super(a)
|
111
|
-
a.icon
|
110
|
+
a.icon = :user_edit
|
112
111
|
end
|
113
112
|
|
114
113
|
action :delete do |a|
|
115
114
|
super(a)
|
116
|
-
a.icon
|
115
|
+
a.icon = :user_delete
|
117
116
|
end
|
118
117
|
|
119
118
|
def default_context_menu
|
@@ -121,47 +120,49 @@ class Marty::UserView < Marty::Grid
|
|
121
120
|
end
|
122
121
|
|
123
122
|
attribute :login do |c|
|
124
|
-
c.width
|
125
|
-
c.label
|
123
|
+
c.width = 100
|
124
|
+
c.label = I18n.t("user_grid.login")
|
126
125
|
end
|
127
126
|
|
128
127
|
attribute :firstname do |c|
|
129
|
-
c.width
|
130
|
-
c.label
|
128
|
+
c.width = 100
|
129
|
+
c.label = I18n.t("user_grid.firstname")
|
131
130
|
end
|
132
131
|
|
133
132
|
attribute :lastname do |c|
|
134
|
-
c.width
|
135
|
-
c.label
|
133
|
+
c.width = 100
|
134
|
+
c.label = I18n.t("user_grid.lastname")
|
136
135
|
end
|
137
136
|
|
138
137
|
attribute :active do |c|
|
139
|
-
c.width
|
140
|
-
c.label
|
138
|
+
c.width = 60
|
139
|
+
c.label = I18n.t("user_grid.active")
|
141
140
|
end
|
142
141
|
|
143
142
|
attribute :roles do |c|
|
144
|
-
c.width
|
145
|
-
c.flex
|
143
|
+
c.width = 100
|
144
|
+
c.flex = 1
|
146
145
|
c.label = I18n.t("user_grid.roles")
|
147
|
-
c.type
|
146
|
+
c.type = :string,
|
148
147
|
|
149
148
|
c.getter = lambda do |r|
|
150
149
|
r.roles.map { |ur| I18n.t("roles.#{ur.name}") }.sort
|
151
150
|
end
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
|
152
|
+
c.editor_config = {
|
153
|
+
multi_select: true,
|
154
|
+
empty_text: I18n.t("user_grid.select_roles"),
|
155
|
+
store: Role.pluck(:name).map {|n| I18n.t("roles.#{n}")}.sort,
|
156
|
+
type: :string,
|
157
|
+
xtype: :combo,
|
158
|
+
}
|
158
159
|
end
|
159
160
|
|
160
161
|
attribute :created_dt do |c|
|
161
|
-
c.label
|
162
|
+
c.label = I18n.t("user_grid.created_dt")
|
162
163
|
c.format = "Y-m-d H:i"
|
163
164
|
c.read_only = true
|
164
165
|
end
|
165
|
-
end
|
166
|
+
end; end
|
166
167
|
|
167
168
|
UserView = Marty::UserView
|
@@ -4,7 +4,9 @@ module Marty
|
|
4
4
|
|
5
5
|
def index
|
6
6
|
if action_methods.include?(params[:testop].to_s)
|
7
|
-
|
7
|
+
send(params[:testop])
|
8
|
+
elsif params[:testop] == 'env'
|
9
|
+
send('environment')
|
8
10
|
else
|
9
11
|
render file: 'public/404', status: 404, layout: false
|
10
12
|
end
|
@@ -15,6 +17,40 @@ module Marty
|
|
15
17
|
[Diagnostic.new('Marty Version', true, VERSION)]
|
16
18
|
end
|
17
19
|
|
20
|
+
def environment
|
21
|
+
rbv = "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})"
|
22
|
+
|
23
|
+
details = [
|
24
|
+
Diagnostic.new('Environment', true, Rails.env),
|
25
|
+
Diagnostic.new('Rails Version', true, Rails.version),
|
26
|
+
Diagnostic.new('Netzke Core Version', true, Netzke::Core::VERSION),
|
27
|
+
Diagnostic.new('Netzke Basepack Version', true,
|
28
|
+
Netzke::Basepack::VERSION),
|
29
|
+
Diagnostic.new('Ruby Version', true, rbv),
|
30
|
+
Diagnostic.new('RubyGems Version', true, Gem::VERSION),
|
31
|
+
Diagnostic.new('Database Adapter', true,
|
32
|
+
ActiveRecord::Base.connection.adapter_name)
|
33
|
+
]
|
34
|
+
begin
|
35
|
+
status = true
|
36
|
+
result = ActiveRecord::Base.connection.execute('SELECT VERSION();')
|
37
|
+
message = result[0]['version'] if result
|
38
|
+
rescue => e
|
39
|
+
status = false
|
40
|
+
message = e.message
|
41
|
+
end
|
42
|
+
details << Diagnostic.new('Database Version', status, message)
|
43
|
+
|
44
|
+
begin
|
45
|
+
status, message = true, ActiveRecord::Migrator.current_version
|
46
|
+
rescue => e
|
47
|
+
status = false
|
48
|
+
message = e.message
|
49
|
+
end
|
50
|
+
details << Diagnostic.new('Database Schema Version', status, message)
|
51
|
+
diag_response details
|
52
|
+
end
|
53
|
+
|
18
54
|
private
|
19
55
|
def diag_response details
|
20
56
|
if @aggregate_diags
|
@@ -34,8 +34,8 @@ class Marty::DataGrid < Marty::Base
|
|
34
34
|
dg.metadata.each do
|
35
35
|
|inf|
|
36
36
|
|
37
|
-
attr, type, keys,
|
38
|
-
inf["attr"], inf["type"], inf["keys"], inf["
|
37
|
+
attr, type, keys, rs_keep =
|
38
|
+
inf["attr"], inf["type"], inf["keys"], inf["rs_keep"]
|
39
39
|
|
40
40
|
unless rs_keep.nil? || rs_keep.empty?
|
41
41
|
m = /\A *(<|<=|>|>=)? *([a-z_]+) *\z/.match(rs_keep)
|
@@ -197,35 +197,35 @@ class Marty::DataGrid < Marty::Base
|
|
197
197
|
# This would prefer more specific rather than wild card
|
198
198
|
# solutions. However, would need to figure out how to preserve
|
199
199
|
# ordering on subsequent INTERSECT operations.
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
200
|
+
ix_class.
|
201
|
+
select(:index).
|
202
|
+
distinct.
|
203
|
+
where(data_grid_id: group_id,
|
204
|
+
created_dt: created_dt,
|
205
|
+
attr: inf["attr"],
|
206
|
+
).
|
207
|
+
where(q, v).to_sql
|
208
208
|
end.compact
|
209
209
|
|
210
210
|
sql = sqla.join(" INTERSECT ")
|
211
211
|
|
212
|
-
self.class.connection.execute(sql).to_a.map { |
|
212
|
+
self.class.connection.execute(sql).to_a.map { |hh| hh["index"].to_i }
|
213
213
|
end
|
214
214
|
|
215
215
|
def lookup_grid_distinct(pt, h, return_grid_data=false, distinct=true)
|
216
|
-
isets = ["h", "v"].each_with_object({}) do |dir,
|
216
|
+
isets = ["h", "v"].each_with_object({}) do |dir, ih|
|
217
217
|
infos = dir_infos(dir)
|
218
218
|
|
219
|
-
|
219
|
+
ih[dir] = query_grid_dir(h, infos)
|
220
220
|
|
221
|
-
unless
|
221
|
+
unless ih[dir] or return_grid_data
|
222
222
|
attrs = infos.map { |inf| inf["attr"] }
|
223
223
|
|
224
224
|
raise "#{dir} attrs not provided: %s" % attrs.join(',')
|
225
225
|
end
|
226
226
|
|
227
|
-
raise "Grid #{name}, (#{
|
228
|
-
distinct &&
|
227
|
+
raise "Grid #{name}, (#{ih[dir].count}) #{dir} matches > 1." if
|
228
|
+
distinct && ih[dir] && ih[dir].count > 1
|
229
229
|
end
|
230
230
|
|
231
231
|
# deterministic result: pick min index when there's a choice
|
@@ -349,7 +349,7 @@ class Marty::DataGrid < Marty::Base
|
|
349
349
|
dt_row = lenient ? ["lenient"] : []
|
350
350
|
dt_row << data_type unless [nil, DEFAULT_DATA_TYPE].member?(data_type)
|
351
351
|
|
352
|
-
meta_rows = dt_row.empty? ? [] : [dt_row]
|
352
|
+
meta_rows = dt_row.empty? ? [] : [[dt_row.join(' ')]]
|
353
353
|
|
354
354
|
meta_rows += metadata.map { |inf|
|
355
355
|
[inf["attr"], inf["type"], inf["dir"], inf["rs_keep"] || ""]
|
@@ -435,7 +435,7 @@ class Marty::DataGrid < Marty::Base
|
|
435
435
|
|
436
436
|
def self.maybe_get_klass(type)
|
437
437
|
begin
|
438
|
-
|
438
|
+
type.constantize unless INDEX_MAP[type] || type == "float"
|
439
439
|
rescue NameError
|
440
440
|
raise "unknown header type/klass: #{type}"
|
441
441
|
end
|
@@ -620,8 +620,8 @@ class Marty::DataGrid < Marty::Base
|
|
620
620
|
metadata_copy, data_copy = metadata.deep_dup, data.deep_dup
|
621
621
|
|
622
622
|
metadata_copy.each do |meta|
|
623
|
-
dir,
|
624
|
-
|
623
|
+
dir, keys, type, rs_keep = meta.values_at(
|
624
|
+
"dir", "keys", "type", "rs_keep")
|
625
625
|
next unless rs_keep
|
626
626
|
|
627
627
|
if type == "numrange" || type == "int4range"
|
data/config/locales/en.yml
CHANGED
@@ -17,6 +17,8 @@ en:
|
|
17
17
|
create_posting: Create
|
18
18
|
api_auth: API Authorization
|
19
19
|
event_view: Event View
|
20
|
+
data_grid_view: Data Grids
|
21
|
+
data_grid: Data Grids
|
20
22
|
|
21
23
|
roles:
|
22
24
|
viewer: Viewer
|
@@ -154,3 +156,6 @@ en:
|
|
154
156
|
api_key: API Key
|
155
157
|
app_name: Application Name
|
156
158
|
script_name: Script Name
|
159
|
+
data_grid__name: Data Grid
|
160
|
+
breakeven_data_grid__name: Breakeven Data Grid
|
161
|
+
data_grid_view: Data Grids
|
data/lib/marty/version.rb
CHANGED
@@ -66,5 +66,37 @@ module Marty
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
+
|
70
|
+
describe 'GET #environment' do
|
71
|
+
it 'returns http success' do
|
72
|
+
get :environment
|
73
|
+
|
74
|
+
expect(response).to have_http_status(:success)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns the environment details' do
|
78
|
+
get :environment
|
79
|
+
|
80
|
+
aggregate_failures do
|
81
|
+
expect(assigns('details').count).to eq(9)
|
82
|
+
expect(assigns('details').first.methods)
|
83
|
+
.to include(:name, :status, :description)
|
84
|
+
expect(assigns('details').first.description).to eq('test')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns the appropriate json' do
|
89
|
+
get :environment, format: :json
|
90
|
+
|
91
|
+
aggregate_failures do
|
92
|
+
expect(json_response.first['diag_count']).to eq(9)
|
93
|
+
expect(json_response.first['error_count']).to eq(0)
|
94
|
+
expect(json_response
|
95
|
+
.find { |d| d['name'] == 'Environment' }['description'])
|
96
|
+
.to eq('test')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
69
101
|
end
|
70
102
|
end
|
@@ -699,6 +699,15 @@ EOS
|
|
699
699
|
end
|
700
700
|
end
|
701
701
|
|
702
|
+
describe "exports" do
|
703
|
+
it 'should export lenient grids correctly' do
|
704
|
+
dg = dg_from_import("Gf", Gf)
|
705
|
+
dg2 = dg_from_import("Gf2", dg.export)
|
706
|
+
|
707
|
+
expect(dg.export).to eq(dg2.export)
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
702
711
|
describe "updates" do
|
703
712
|
it "should be possible to modify a grid referenced from a multi-grid" do
|
704
713
|
dgb = dg_from_import("Gb", Gb, '1/1/2014')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2017-
|
17
|
+
date: 2017-02-13 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: pg
|
@@ -178,6 +178,7 @@ files:
|
|
178
178
|
- app/components/marty/auth_app.rb
|
179
179
|
- app/components/marty/auth_app/client/auth_app.js
|
180
180
|
- app/components/marty/config_view.rb
|
181
|
+
- app/components/marty/data_grid_view.rb
|
181
182
|
- app/components/marty/event_view.rb
|
182
183
|
- app/components/marty/extras/layout.rb
|
183
184
|
- app/components/marty/extras/misc.rb
|