engine2 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -0
  3. data/Rakefile +1 -1
  4. data/app/{engine2actions.coffee → actions.coffee} +192 -142
  5. data/app/app.coffee +0 -0
  6. data/app/app.css +4 -0
  7. data/app/engine2.coffee +87 -175
  8. data/app/modal.coffee +133 -0
  9. data/bower.json +2 -1
  10. data/conf/message.yaml +0 -0
  11. data/conf/message_pl.yaml +0 -0
  12. data/config.coffee +11 -2
  13. data/engine2.gemspec +2 -2
  14. data/lib/engine2.rb +12 -10
  15. data/lib/engine2/action.rb +1290 -134
  16. data/lib/engine2/{meta/array_meta.rb → action/array.rb} +4 -3
  17. data/lib/engine2/{meta/decode_meta.rb → action/decode.rb} +16 -15
  18. data/lib/engine2/action/delete.rb +65 -0
  19. data/lib/engine2/action/form.rb +16 -0
  20. data/lib/engine2/{meta/infra_meta.rb → action/infra.rb} +118 -85
  21. data/lib/engine2/action/link.rb +117 -0
  22. data/lib/engine2/{meta/list_meta.rb → action/list.rb} +61 -62
  23. data/lib/engine2/action/save.rb +30 -0
  24. data/lib/engine2/action/view.rb +8 -0
  25. data/lib/engine2/action_node.rb +221 -0
  26. data/lib/engine2/core.rb +120 -77
  27. data/lib/engine2/handler.rb +9 -10
  28. data/lib/engine2/model.rb +4 -20
  29. data/lib/engine2/models/Files.rb +2 -1
  30. data/lib/engine2/models/UserInfo.rb +6 -3
  31. data/lib/engine2/post_bootstrap.rb +3 -2
  32. data/lib/engine2/pre_bootstrap.rb +1 -0
  33. data/lib/engine2/scheme.rb +98 -47
  34. data/lib/engine2/templates.rb +1 -0
  35. data/lib/engine2/type_info.rb +6 -4
  36. data/lib/engine2/version.rb +2 -1
  37. data/package.json +12 -10
  38. data/public/favicon.ico +0 -0
  39. data/public/img/ajax-loader-dark.gif +0 -0
  40. data/public/img/ajax-loader.gif +0 -0
  41. data/views/fields/blob.slim +0 -0
  42. data/views/fields/bs_select.slim +0 -0
  43. data/views/fields/bsselect_picker.slim +0 -0
  44. data/views/fields/bsselect_picker_opt.slim +0 -0
  45. data/views/fields/checkbox.slim +0 -0
  46. data/views/fields/checkbox_buttons.slim +0 -0
  47. data/views/fields/checkbox_buttons_opt.slim +0 -0
  48. data/views/fields/currency.slim +0 -0
  49. data/views/fields/date.slim +0 -0
  50. data/views/fields/date_range.slim +0 -0
  51. data/views/fields/date_time.slim +0 -0
  52. data/views/fields/datetime.slim +0 -0
  53. data/views/fields/decimal.slim +0 -0
  54. data/views/fields/decimal_date.slim +0 -0
  55. data/views/fields/decimal_time.slim +0 -0
  56. data/views/fields/email.slim +0 -0
  57. data/views/fields/file_store.slim +7 -7
  58. data/views/fields/input_text.slim +0 -0
  59. data/views/fields/integer.slim +0 -0
  60. data/views/fields/list_bsselect.slim +0 -0
  61. data/views/fields/list_bsselect_opt.slim +0 -0
  62. data/views/fields/list_buttons.slim +0 -0
  63. data/views/fields/list_buttons_opt.slim +0 -0
  64. data/views/fields/list_select.slim +0 -0
  65. data/views/fields/list_select_opt.slim +0 -0
  66. data/views/fields/password.slim +0 -0
  67. data/views/fields/radio_checkbox.slim +0 -0
  68. data/views/fields/scaffold.slim +0 -0
  69. data/views/fields/scaffold_picker.slim +0 -0
  70. data/views/fields/select_picker.slim +0 -0
  71. data/views/fields/select_picker_opt.slim +0 -0
  72. data/views/fields/text_area.slim +1 -0
  73. data/views/fields/time.slim +0 -0
  74. data/views/fields/typeahead_picker.slim +0 -0
  75. data/views/index.slim +3 -3
  76. data/views/infra/index.slim +0 -0
  77. data/views/infra/inspect.slim +20 -0
  78. data/views/modals/close_m.slim +0 -0
  79. data/views/modals/confirm_m.slim +0 -0
  80. data/views/modals/empty_m.slim +0 -0
  81. data/views/modals/menu_m.slim +1 -1
  82. data/views/modals/yes_no_m.slim +0 -0
  83. data/views/panels/menu_m.slim +1 -1
  84. data/views/scaffold/confirm.slim +0 -0
  85. data/views/scaffold/fields.slim +0 -0
  86. data/views/scaffold/form.slim +0 -0
  87. data/views/scaffold/form_collapse.slim +0 -0
  88. data/views/scaffold/form_tabs.slim +0 -0
  89. data/views/scaffold/list.slim +0 -0
  90. data/views/scaffold/message.slim +0 -0
  91. data/views/scaffold/search.slim +0 -0
  92. data/views/scaffold/search_collapse.slim +0 -0
  93. data/views/scaffold/search_tabs.slim +0 -0
  94. data/views/scaffold/view.slim +0 -0
  95. data/views/scaffold/view_collapse.slim +0 -0
  96. data/views/scaffold/view_tabs.slim +0 -0
  97. data/views/search_fields/bsmselect_picker.slim +0 -0
  98. data/views/search_fields/bsselect_picker.slim +0 -0
  99. data/views/search_fields/checkbox.slim +0 -0
  100. data/views/search_fields/checkbox2.slim +0 -0
  101. data/views/search_fields/checkbox_buttons.slim +0 -0
  102. data/views/search_fields/date_range.slim +0 -0
  103. data/views/search_fields/decimal_date_range.slim +0 -0
  104. data/views/search_fields/input_text.slim +0 -0
  105. data/views/search_fields/integer.slim +0 -0
  106. data/views/search_fields/integer_range.slim +0 -0
  107. data/views/search_fields/list_bsmselect.slim +0 -0
  108. data/views/search_fields/list_bsselect.slim +0 -0
  109. data/views/search_fields/list_buttons.slim +0 -0
  110. data/views/search_fields/list_select.slim +0 -0
  111. data/views/search_fields/scaffold_picker.slim +0 -0
  112. data/views/search_fields/select_picker.slim +0 -0
  113. data/views/search_fields/typeahead_picker.slim +0 -0
  114. metadata +41 -42
  115. data/lib/engine2/meta.rb +0 -1216
  116. data/lib/engine2/meta/delete_meta.rb +0 -60
  117. data/lib/engine2/meta/form_meta.rb +0 -15
  118. data/lib/engine2/meta/link_meta.rb +0 -134
  119. data/lib/engine2/meta/save_meta.rb +0 -50
  120. data/lib/engine2/meta/view_meta.rb +0 -7
  121. data/public/__sinatra__/404.png +0 -0
  122. data/public/__sinatra__/500.png +0 -0
@@ -1,9 +1,10 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Engine2
4
- class ArrayListMeta < Meta
5
- meta_type :list
6
- include MetaListSupport
5
+ class ArrayListAction < Action
6
+ action_type :list
7
+ include ActionListSupport
7
8
 
8
9
  (DefaultFilters ||= {}).merge!(
9
10
  exact: lambda{|entries, name, value, type_info, hash|
@@ -1,8 +1,9 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Engine2
4
- class DecodeMeta < Meta
5
- include MetaAPISupport, MetaModelSupport, MetaQuerySupport
5
+ class DecodeAction < Action
6
+ include ActionAPISupport, ActionModelSupport, ActionQuerySupport
6
7
 
7
8
  def decode *fields, &blk
8
9
  query select(*fields), &blk
@@ -19,7 +20,7 @@ module Engine2
19
20
 
20
21
  def post_process
21
22
  if fields = @meta[:fields]
22
- fields = fields - static.get[:fields] if dynamic?
23
+ fields = fields - static.meta[:fields] if dynamic?
23
24
  # no decorate here
24
25
  fields.each do |name|
25
26
  type_info = assets[:model].type_info[name] # foreign keys ?
@@ -42,7 +43,7 @@ module Engine2
42
43
  end
43
44
 
44
45
  def post_run
45
- query select(*assets[:model].primary_keys) unless @query
46
+ decode(*assets[:model].primary_keys) unless @query
46
47
  @meta[:separator] = '/' unless @meta[:separator]
47
48
  super
48
49
  @meta[:primary_fields] = assets[:model].primary_keys
@@ -50,16 +51,16 @@ module Engine2
50
51
 
51
52
  end
52
53
 
53
- class DecodeListMeta < DecodeMeta
54
- meta_type :decode_list
54
+ class DecodeListAction < DecodeAction
55
+ action_type :decode_list
55
56
 
56
57
  def invoke handler
57
58
  {entries: get_query.limit(200).all}
58
59
  end
59
60
  end
60
61
 
61
- class TypeAheadMeta < DecodeMeta
62
- meta_type :typeahead
62
+ class TypeAheadAction < DecodeAction
63
+ action_type :typeahead
63
64
 
64
65
  def pre_run
65
66
  super
@@ -72,7 +73,7 @@ module Engine2
72
73
 
73
74
  def invoke handler
74
75
  if query = handler.params[:query]
75
- condition = (@meta[:decode_fields] || @meta[:fields]).map{|f|f.like("%#{query}%")}.inject{|q, f| q | f}
76
+ condition = @meta[:decode_fields].map{|f|f.like("%#{query}%")}.reduce{|q, f| q | f}
76
77
  {entries: get_query.where(condition).limit(@meta[:limit]).all}
77
78
  else
78
79
  handler.permit id = handler.params[:id]
@@ -83,15 +84,15 @@ module Engine2
83
84
  end
84
85
  end
85
86
 
86
- class DecodeEntryMeta < DecodeMeta
87
- meta_type :decode_entry
87
+ class DecodeEntryAction < DecodeAction
88
+ action_type :decode_entry
88
89
 
89
90
  def invoke handler
90
91
  {entries: invoke_decode(handler, handler.param_to_json(:ids))}
91
92
  end
92
93
 
93
94
  def invoke_decode handler, ids
94
- records = get_query.where(ids.map{|keys| Hash[assets[:model].primary_keys.zip(keys)]}.inject{|q, c| q | c}).all
95
+ records = get_query.where(ids.map{|keys| Hash[assets[:model].primary_keys.zip(keys)]}.reduce{|q, c| q | c}).all
95
96
  # handler.halt_not_found(LOCS[:no_entry]) if records.empty?
96
97
  records
97
98
  end
@@ -101,9 +102,9 @@ module Engine2
101
102
  if assoc = assets[:assoc]
102
103
  decode = assoc[:model].type_info[assoc[:keys].first][:decode]
103
104
 
104
- if decode[:search][:multiple] && action.parent.parent.*.is_a?(ListMeta)
105
- action.list.*.menu(:panel_menu).option :choose, icon: :ok #, disabled: "action.selected_size() == 0"
106
- action.list.*.menu(:panel_menu).option :cancel, icon: "remove"
105
+ if decode[:search][:multiple] && node.parent.parent.*.is_a?(ListAction)
106
+ node.list.*.menu(:panel_menu).option :choose, icon: :ok #, disabled: "action.selected_size() == 0"
107
+ node.list.*.menu(:panel_menu).option :cancel, icon: "remove"
107
108
  end
108
109
  end
109
110
  end
@@ -0,0 +1,65 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Engine2
5
+ class DeleteActionBase < Action
6
+ def invoke_delete_db handler, ids, from_assoc = nil
7
+ model = assets[:model]
8
+ model.db.transaction do
9
+ ids.each do |id|
10
+ keys = split_keys(id)
11
+
12
+ model.association_reflections.each do |name, assoc|
13
+ ds = case assoc[:type]
14
+ when :one_to_one
15
+ when :one_to_many
16
+ model.db[assoc.associated_class.table_name].where(Hash[assoc[:keys].zip(keys)])
17
+ when :many_to_many
18
+ model.db[assoc[:join_table]].where(Hash[assoc[:left_keys].zip(keys)])
19
+ when :many_to_one
20
+ nil
21
+ else
22
+ unsupported_association assoc[:type]
23
+ end
24
+
25
+ if assoc[:cascade] || from_assoc == assoc.associated_class.table_name
26
+ ds.delete
27
+ else
28
+ raise Sequel::DestroyFailed.new("#{LOCS[:delete_restricted]}: #{name}") unless ds.empty?
29
+ end if ds
30
+ end
31
+
32
+ rec = model.call(Hash[model.primary_keys.zip(keys)])
33
+ rec.destroy(transaction: false)
34
+ # model.where(model.primary_keys_hash(keys)).delete # model.dataset[model.primary_key => id].delete
35
+ end
36
+ end
37
+
38
+ rescue Sequel::NoExistingObject
39
+ handler.halt_not_found LOCS[:no_entry]
40
+ rescue Sequel::DestroyFailed => failure
41
+ handler.halt_forbidden failure.error.to_s
42
+ {}
43
+ end
44
+ end
45
+
46
+ class DeleteAction < DeleteActionBase
47
+ include ActionDeleteSupport
48
+
49
+ def invoke handler
50
+ handler.permit id = handler.params[:id]
51
+ invoke_delete_db(handler, [id])
52
+ end
53
+ end
54
+
55
+ class BulkDeleteAction < DeleteActionBase
56
+ include ActionBulkDeleteSupport
57
+
58
+ def invoke handler
59
+ ids = handler.param_to_json(:ids)
60
+ handler.permit ids.is_a?(Array)
61
+ invoke_delete_db(handler, ids)
62
+ end
63
+ end
64
+
65
+ end
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Engine2
5
+ class FormAction < Action
6
+ include ActionQuerySupport
7
+ end
8
+
9
+ class CreateAction < FormAction
10
+ include ActionCreateSupport
11
+ end
12
+
13
+ class ModifyAction < FormAction
14
+ include ActionModifySupport
15
+ end
16
+ end
@@ -1,61 +1,43 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Engine2
4
- SCHEMES::define_scheme :infra! do |user_info_model = UserInfo|
5
- define_action :infra! do
6
- self.* do
7
- extend MetaPanelSupport, MetaMenuSupport, MetaAPISupport
8
- panel_panel_template false
9
- panel_template 'infra/index'
10
- loc! logged_on: LOCS[:logged_on]
11
- menu :menu do
12
- properties group_class: "btn-group-sm"
13
- option :inspect_modal, icon: :wrench, button_loc: false # , show: "action.logged_on"
14
-
15
- option :logout_form, icon: :"log-out" # , show: "action.logged_on"
16
- option :login_form, icon: :"log-in", disabled: 'action.action_pending()' # , show: "!action.logged_on"
17
- end
18
-
19
- @meta_type = :infra
20
-
21
- define_invoke do |handler|
22
- user = handler.user
23
- {user: user ? user.to_hash : nil}
24
- end
25
- end
5
+ SCHEMES::define_scheme :login! do |user_info_model = UserInfo|
6
+ define_node :login_form, LoginFormAction, model: user_info_model do
7
+ access!{|h|!h.logged_in?}
8
+ define_node :login, LoginAction
9
+ end
10
+ end
26
11
 
27
- define_action :login_form, LoginFormMeta, model: user_info_model do
28
- access!{|h|!h.logged_in?}
29
- define_action :login, LoginMeta
30
- end
12
+ SCHEMES::define_scheme :logout! do
13
+ define_node :logout_form, LogoutFormAction do
14
+ access! &:logged_in?
15
+ define_node :logout, LogoutAction
16
+ end
17
+ end
31
18
 
32
- define_action :logout_form, LogoutFormMeta do
33
- access! &:logged_in?
34
- define_action :logout, LogoutMeta
35
- end
19
+ SCHEMES::define_scheme :infra! do |user_info_model = UserInfo|
20
+ run_scheme :login!, user_info_model
21
+ define_node :infra!, InfraAction do
22
+ run_scheme :login!, user_info_model
23
+ run_scheme :logout!
36
24
 
37
- define_action :inspect_modal do
25
+ define_node :inspect_modal, InspectModalAction do
38
26
  access! &:logged_in?
39
- # access!{|h|h.user[:name] == 'admin'}
40
- self.* do
41
- extend MetaPanelSupport, MetaMenuSupport
42
- modal_action
43
- panel_template 'infra/inspect'
44
- panel_title "#{:wrench.icon} Inspect"
45
- panel_class "modal-huge"
46
- panel[:backdrop] = true
47
- menu(:panel_menu).option :cancel, icon: "remove"
48
- end
49
- define_action :inspect do
27
+ define_node :inspect, WebSocketAction.inherit do
50
28
  self.* do
51
- @meta_type = :inspect
29
+ @action_type = :inspect
30
+
31
+ ws_message do |msg, ws|
32
+ ws.send! number: msg[:number].to_i + 1
33
+ end
52
34
  end
53
35
 
54
- define_action_invoke :models do |handler|
36
+ define_invoke :models do |handler|
55
37
  {models: Sequel::DATABASES.map{|db| {name: db.uri, models: db.models.keys} }}
56
38
  end
57
39
 
58
- define_action_invoke :model_info do |handler|
40
+ define_invoke :model_info do |handler|
59
41
  db_name = handler.params[:db]
60
42
  handler.permit db = Sequel::DATABASES.find{|d|d.uri == db_name || (d.uri && d.uri.start_with?(db_name))}
61
43
  handler.permit model = db.models[handler.params[:model].to_sym]
@@ -71,18 +53,22 @@ module Engine2
71
53
  }
72
54
  }
73
55
  end
56
+
57
+ define_invoke :environment do |handler|
58
+ {environment: handler.env}
59
+ end
74
60
  end
75
61
  end
76
62
  end
77
63
  end
78
64
 
79
65
  SCHEMES::define_scheme :menu! do
80
- define_action :menu!, MenuMeta do
66
+ define_node :menu!, MenuAction do
81
67
  end
82
68
  end
83
69
 
84
- class FileStoreMeta < Meta
85
- meta_type :file_store
70
+ class FileStoreAction < Action
71
+ action_type :file_store
86
72
 
87
73
  attr_accessor :model, :field
88
74
 
@@ -93,7 +79,7 @@ module Engine2
93
79
  end
94
80
 
95
81
 
96
- module BlobSupportMeta
82
+ module BlobSupportAction
97
83
  def serve_blob handler, entry, inf
98
84
  handler.permit entry
99
85
  handler.attachment entry[inf[:name_field]]
@@ -102,8 +88,8 @@ module Engine2
102
88
  end
103
89
  end
104
90
 
105
- class DownloadFileStoreMeta < Meta
106
- meta_type :download
91
+ class DownloadFileStoreAction < Action
92
+ action_type :download
107
93
 
108
94
  def invoke handler
109
95
  handler.permit id = handler.params[:id]
@@ -111,28 +97,28 @@ module Engine2
111
97
  handler.permit entry
112
98
  handler.attachment entry[:name]
113
99
  handler.content_type (entry[:mime].to_s.empty? ? "application/octet-stream" : entry[:mime])
114
- info = action.parent.*.model.type_info[action.parent.*.field]
100
+ info = node.parent.*.model.type_info[node.parent.*.field]
115
101
  open("#{info[:store][:files]}/#{entry[:name]}_#{id}", 'rb'){|f|f.read}
116
102
  end
117
103
  end
118
104
 
119
- class UploadFileStoreMeta < Meta
105
+ class UploadFileStoreAction < Action
120
106
  http_method :post
121
- meta_type :upload
107
+ action_type :upload
122
108
 
123
109
  def invoke handler
124
110
  file = handler.params[:file]
125
111
  temp = file[:tempfile]
126
112
  temp.close
127
113
  rackname = File.basename(temp.path)
128
- info = action.parent.*.model.type_info[action.parent.*.field]
114
+ info = node.parent.*.model.type_info[node.parent.*.field]
129
115
  File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
130
116
  {rackname: rackname}
131
117
  end
132
118
  end
133
119
 
134
- class BlobStoreMeta < Meta
135
- meta_type :blob_store
120
+ class BlobStoreAction < Action
121
+ action_type :blob_store
136
122
 
137
123
  attr_accessor :model, :field
138
124
 
@@ -145,13 +131,13 @@ module Engine2
145
131
  end
146
132
  end
147
133
 
148
- class DownloadBlobStoreMeta < Meta
149
- include BlobSupportMeta
150
- meta_type :download_blob
134
+ class DownloadBlobStoreAction < Action
135
+ include BlobSupportAction
136
+ action_type :download_blob
151
137
 
152
138
  def invoke handler
153
- model = action.parent.*.model
154
- inf = model.type_info[action.parent.*.field]
139
+ model = node.parent.*.model
140
+ inf = model.type_info[node.parent.*.field]
155
141
  handler.permit id = handler.params[:id]
156
142
 
157
143
  entry = model.naked.select(inf[:bytes_field], inf[:name_field], inf[:mime_field]).where(model.primary_keys_hash(split_keys(id))).first
@@ -159,23 +145,23 @@ module Engine2
159
145
  end
160
146
  end
161
147
 
162
- class UploadBlobStoreMeta < Meta
148
+ class UploadBlobStoreAction < Action
163
149
  http_method :post
164
- meta_type :upload_blob
150
+ action_type :upload_blob
165
151
 
166
152
  def invoke handler
167
153
  file = handler.params[:file]
168
154
  temp = file[:tempfile]
169
155
  temp.close
170
156
  rackname = File.basename(temp.path)
171
- info = action.parent.*.model.type_info[action.parent.*.field]
157
+ info = node.parent.*.model.type_info[node.parent.*.field]
172
158
  File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
173
159
  {rackname: rackname}
174
160
  end
175
161
  end
176
162
 
177
- class ForeignBlobStoreMeta < Meta
178
- meta_type :blob_store
163
+ class ForeignBlobStoreAction < Action
164
+ action_type :blob_store
179
165
 
180
166
  attr_accessor :model, :field
181
167
 
@@ -195,13 +181,13 @@ module Engine2
195
181
  end
196
182
  end
197
183
 
198
- class DownloadForeignBlobStoreMeta < Meta
199
- include BlobSupportMeta
200
- meta_type :download_blob
184
+ class DownloadForeignBlobStoreAction < Action
185
+ include BlobSupportAction
186
+ action_type :download_blob
201
187
 
202
188
  def invoke handler
203
- model = action.parent.*.model
204
- inf = model.type_info[action.parent.*.field]
189
+ model = node.parent.*.model
190
+ inf = model.type_info[node.parent.*.field]
205
191
  assoc = model.association_reflections[inf[:assoc_name]]
206
192
  blob_model = assoc.associated_class
207
193
  handler.permit id = handler.params[:id]
@@ -213,9 +199,9 @@ module Engine2
213
199
  end
214
200
  end
215
201
 
216
- # class UploadForeignBlobStoreMeta < Meta
202
+ # class UploadForeignBlobStoreAction < Action
217
203
  # http_method :post
218
- # meta_type :upload_blob
204
+ # action_type :upload_blob
219
205
 
220
206
  # def invoke handler
221
207
  # file = handler.params[:file]
@@ -227,9 +213,51 @@ module Engine2
227
213
  # end
228
214
  # end
229
215
 
230
- class LoginFormMeta < Meta
231
- include MetaFormSupport
232
- meta_type :login_form
216
+ class InfraAction < Action
217
+ include ActionPanelSupport, ActionMenuSupport, ActionAPISupport
218
+ action_type :infra
219
+
220
+ def pre_run
221
+ super
222
+ panel_panel_template false
223
+ panel_template 'infra/index'
224
+ loc! logged_on: LOCS[:logged_on]
225
+ menu :menu do
226
+ properties group_class: "btn-group-sm"
227
+ option :inspect_modal, icon: :wrench, button_loc: false # , show: "action.logged_on"
228
+ end
229
+ end
230
+
231
+ def invoke handler
232
+ user = handler.user
233
+ {user: user ? user.to_hash : nil}
234
+ end
235
+
236
+ def login_meta show_login_otion = 'false', &blk
237
+ node.login_form.* &blk
238
+ menu(:menu).modify_option :login_form, show: show_login_otion
239
+ node.parent.login_form.* &blk
240
+ end
241
+ end
242
+
243
+ class InspectModalAction < Action
244
+ include ActionPanelSupport, ActionMenuSupport
245
+ action_type :inline
246
+
247
+ def pre_run
248
+ super
249
+ modal_action
250
+ panel_template 'infra/inspect'
251
+ panel_title "#{:wrench.icon} Inspect"
252
+ panel_class "modal-huge"
253
+ panel[:backdrop] = true
254
+ menu(:panel_menu).option :cancel, icon: "remove"
255
+ end
256
+ end
257
+
258
+ class LoginFormAction < Action
259
+ include ActionFormSupport
260
+ action_type :login_form
233
261
 
234
262
  def pre_run
235
263
  super
@@ -238,6 +266,10 @@ module Engine2
238
266
  info! :name, loc: LOCS[:user_name]
239
267
  menu(:panel_menu).modify_option :approve, name: :login, icon: :"log-in"
240
268
  @meta[:fields] = [:name, :password]
269
+ parent_action = node.parent.*
270
+ if parent_action.is_a? ActionMenuSupport
271
+ parent_action.menu(:menu).option :login_form, icon: :"log-in", disabled: "action.action_pending()"
272
+ end
241
273
  end
242
274
 
243
275
  def invoke handler
@@ -245,9 +277,9 @@ module Engine2
245
277
  end
246
278
  end
247
279
 
248
- class LoginMeta < Meta
249
- include MetaApproveSupport
250
- meta_type :login
280
+ class LoginAction < Action
281
+ include ActionApproveSupport
282
+ action_type :login
251
283
 
252
284
  def validate_record handler, record
253
285
  super
@@ -263,15 +295,16 @@ module Engine2
263
295
  end
264
296
  end
265
297
 
266
- class LogoutFormMeta < Meta
267
- include MetaPanelSupport, MetaMenuSupport
268
- meta_type :logout_form
298
+ class LogoutFormAction < Action
299
+ include ActionPanelSupport, ActionMenuSupport
300
+ action_type :logout_form
269
301
  def pre_run
270
302
  super
271
303
  panel_template 'scaffold/message'
272
304
  panel_title LOCS[:logout_title]
273
305
  panel_class 'modal-default'
274
306
  @meta[:message] = LOCS[:logout_message]
307
+ node.parent.*.menu(:menu).option :logout_form, icon: :"log-out" # , show: "action.logged_on"
275
308
  menu :panel_menu do
276
309
  option :logout, icon: "ok", loc: LOCS[:ok]
277
310
  option :cancel, icon: "remove"
@@ -279,8 +312,8 @@ module Engine2
279
312
  end
280
313
  end
281
314
 
282
- class LogoutMeta < Meta
283
- meta_type :logout
315
+ class LogoutAction < Action
316
+ action_type :logout
284
317
 
285
318
  def invoke handler
286
319
  handler.session.clear