engine2 1.0.4 → 1.0.5

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 (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