netzke-basepack 0.6.3 → 0.6.4

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 (98) hide show
  1. data/CHANGELOG.rdoc +17 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +3 -0
  4. data/TODO.rdoc +1 -4
  5. data/features/form_panel.feature +2 -1
  6. data/features/grid_panel.feature +134 -5
  7. data/features/nested_attributes.feature +4 -1
  8. data/features/paging_form_panel.feature +41 -0
  9. data/features/search_in_grid.feature +20 -7
  10. data/features/step_definitions/form_panel_steps.rb +35 -0
  11. data/features/step_definitions/generic_steps.rb +20 -1
  12. data/features/step_definitions/grid_panel_steps.rb +63 -0
  13. data/features/support/env.rb +4 -0
  14. data/features/validations_in_grid.feature +13 -0
  15. data/features/virtual_attributes.feature +5 -9
  16. data/javascripts/basepack.js +21 -650
  17. data/javascripts/datetimefield.js +24 -0
  18. data/lib/generators/netzke/basepack_generator.rb +10 -0
  19. data/{generators/netzke_basepack/templates/public_assets → lib/generators/netzke/templates/assets}/ts-checkbox.gif +0 -0
  20. data/{generators/netzke_basepack → lib/generators/netzke}/templates/create_netzke_field_lists.rb +0 -0
  21. data/lib/netzke-basepack.rb +3 -41
  22. data/lib/netzke/active_record/attributes.rb +17 -21
  23. data/lib/netzke/basepack.rb +6 -1
  24. data/lib/netzke/basepack/data_accessor.rb +166 -0
  25. data/lib/netzke/basepack/form_panel.rb +69 -20
  26. data/lib/netzke/basepack/form_panel/fields.rb +15 -17
  27. data/lib/netzke/basepack/form_panel/javascripts/comma_list_cbg.js +7 -0
  28. data/lib/netzke/basepack/form_panel/javascripts/display_mode.js +6 -0
  29. data/lib/netzke/basepack/form_panel/javascripts/{main.js → form_panel.js} +42 -8
  30. data/lib/netzke/basepack/form_panel/javascripts/n_radio_group.js +24 -7
  31. data/lib/netzke/basepack/form_panel/javascripts/readonly_mode.js +52 -0
  32. data/lib/netzke/basepack/form_panel/services.rb +28 -2
  33. data/lib/netzke/basepack/form_panel/stylesheets/readonly_mode.css +14 -0
  34. data/lib/netzke/basepack/grid_panel.rb +151 -181
  35. data/lib/netzke/basepack/grid_panel/columns.rb +122 -84
  36. data/lib/netzke/basepack/grid_panel/javascripts/advanced_search.js +22 -27
  37. data/lib/netzke/basepack/grid_panel/javascripts/{main.js → grid_panel.js} +182 -108
  38. data/lib/netzke/basepack/grid_panel/record_form_window.rb +7 -2
  39. data/lib/netzke/basepack/grid_panel/services.rb +58 -39
  40. data/lib/netzke/basepack/paging_form_panel.rb +86 -25
  41. data/lib/netzke/basepack/query_builder.rb +105 -0
  42. data/lib/netzke/basepack/query_builder/javascripts/query_builder.js +140 -0
  43. data/lib/netzke/basepack/search_panel.rb +61 -44
  44. data/lib/netzke/basepack/search_panel/javascripts/condition_field.js +153 -0
  45. data/lib/netzke/basepack/search_panel/javascripts/search_panel.js +64 -0
  46. data/lib/netzke/basepack/search_window.rb +64 -0
  47. data/lib/netzke/basepack/simple_app.rb +1 -1
  48. data/lib/netzke/basepack/simple_app/javascripts/{main.js → simple_app.js} +0 -0
  49. data/lib/netzke/basepack/tab_panel.rb +1 -2
  50. data/lib/netzke/basepack/tab_panel/javascripts/{main.js → tab_panel.js} +0 -0
  51. data/lib/netzke/basepack/version.rb +1 -1
  52. data/locales/en.yml +71 -4
  53. data/netzke-basepack.gemspec +47 -22
  54. data/spec/active_record/attributes_spec.rb +6 -6
  55. data/spec/components/form_panel_spec.rb +2 -13
  56. data/stylesheets/datetimefield.css +54 -0
  57. data/test/rails_app/Gemfile +3 -3
  58. data/test/rails_app/Gemfile.lock +67 -57
  59. data/test/rails_app/README +1 -256
  60. data/test/rails_app/app/components/book_form.rb +1 -3
  61. data/test/rails_app/app/components/book_form_with_custom_fields.rb +20 -0
  62. data/test/rails_app/app/components/book_form_with_nested_attributes.rb +18 -0
  63. data/test/rails_app/app/components/book_grid.rb +3 -1
  64. data/test/rails_app/app/components/book_grid_loader.rb +24 -0
  65. data/test/rails_app/app/components/book_grid_with_custom_columns.rb +28 -0
  66. data/test/rails_app/app/components/book_grid_with_default_values.rb +1 -1
  67. data/test/rails_app/app/components/book_grid_with_virtual_attributes.rb +0 -1
  68. data/test/rails_app/app/components/book_paging_form_panel.rb +3 -2
  69. data/test/rails_app/app/components/book_presentation.rb +3 -3
  70. data/test/rails_app/app/components/book_query_builder.rb +8 -0
  71. data/test/rails_app/app/components/book_search_panel.rb +5 -0
  72. data/test/rails_app/app/components/book_search_panel/javascripts/i18n_de.js +6 -0
  73. data/test/rails_app/app/components/double_book_grid.rb +18 -0
  74. data/test/rails_app/app/components/form_without_model.rb +1 -1
  75. data/test/rails_app/app/components/paging_form_with_search.rb +39 -0
  76. data/test/rails_app/app/components/user_grid.rb +1 -1
  77. data/test/rails_app/app/models/author.rb +1 -0
  78. data/test/rails_app/config/application.rb +6 -1
  79. data/test/rails_app/config/database.yml +7 -5
  80. data/test/rails_app/config/environments/test.rb +1 -1
  81. data/test/rails_app/config/locales/de.yml +35 -0
  82. data/test/rails_app/config/locales/es.yml +84 -8
  83. data/test/rails_app/db/migrate/20101026190021_create_books.rb +2 -2
  84. data/test/rails_app/db/migrate/20110213213050_create_netzke_component_states.rb +20 -0
  85. data/test/rails_app/db/schema.rb +2 -18
  86. data/test/rails_app/public/netzke/basepack/ts-checkbox.gif +0 -0
  87. data/test/unit/active_record_basepack_test.rb +1 -1
  88. metadata +46 -45
  89. data/generators/netzke_basepack/netzke_basepack_generator.rb +0 -13
  90. data/lib/netzke/basepack/grid_panel/search_window.rb +0 -56
  91. data/lib/netzke/data_accessor.rb +0 -113
  92. data/lib/netzke/ext.rb +0 -7
  93. data/lib/netzke/fields_configurator.rb +0 -170
  94. data/lib/netzke/json_array_editor.rb +0 -67
  95. data/lib/netzke/masquerade_selector.rb +0 -53
  96. data/test/rails_app/app/components/some_search_panel.rb +0 -34
  97. data/test/rails_app/db/development_structure.sql +0 -93
  98. data/test/rails_app/db/migrate/20100905214933_create_netzke_preferences.rb +0 -16
@@ -9,8 +9,13 @@ module Netzke
9
9
  :auto_height => true,
10
10
  :fbar => [:ok.action, :cancel.action]
11
11
 
12
- action :ok, :text => 'OK'
13
- action :cancel
12
+ action :ok do
13
+ { :text => I18n.t('netzke.basepack.grid_panel.record_form_window.actions.ok')}
14
+ end
15
+
16
+ action :cancel do
17
+ { :text => I18n.t('netzke.basepack.grid_panel.record_form_window.actions.cancel')}
18
+ end
14
19
 
15
20
  js_method :init_component, <<-JS
16
21
  function(params){
@@ -45,30 +45,33 @@ module Netzke
45
45
  end
46
46
 
47
47
  endpoint :resize_column do |params|
48
- raise "Called api_resize_column while not configured to do so" if config[:enable_column_resize] == false
49
- columns[normalize_index(params[:index].to_i)][:width] = params[:size].to_i
50
- save_columns!
48
+ raise "Called api_resize_column while not configured to do so" if !config[:persistence]
49
+ current_columns_order = state[:columns_order] || initial_columns_order
50
+ current_columns_order[normalize_index(params[:index].to_i)][:width] = params[:size].to_i
51
+ update_state(:columns_order, current_columns_order)
51
52
  {}
52
53
  end
53
54
 
54
55
  endpoint :move_column do |params|
55
- raise "Called api_move_column while not configured to do so" if config[:enable_column_move] == false
56
+ raise "Called api_move_column while not configured to do so" if !config[:persistence]
56
57
  remove_from = normalize_index(params[:old_index].to_i)
57
58
  insert_to = normalize_index(params[:new_index].to_i)
58
- column_to_move = columns.delete_at(remove_from)
59
- columns.insert(insert_to, column_to_move)
60
- save_columns!
61
59
 
62
- # reorder the columns on the client side (still not sure if it's not an overkill)
63
- # {:reorder_columns => columns.map(&:name)} # Well, I think it IS an overkill - commented out
64
- # until proven to be necessary
60
+ current_columns_order = state[:columns_order] || initial_columns_order
61
+
62
+ column_to_move = current_columns_order.delete_at(remove_from)
63
+ current_columns_order.insert(insert_to, column_to_move)
64
+
65
+ update_state(:columns_order, current_columns_order)
66
+
65
67
  {}
66
68
  end
67
69
 
68
70
  endpoint :hide_column do |params|
69
- raise "Called api_hide_column while not configured to do so" if config[:enable_column_hide] == false
70
- columns[normalize_index(params[:index].to_i)][:hidden] = params[:hidden].to_b
71
- save_columns!
71
+ raise "Called api_hide_column while not configured to do so" if !config[:persistence]
72
+ current_columns_order = state[:columns_order] || initial_columns_order
73
+ current_columns_order[normalize_index(params[:index].to_i)][:hidden] = params[:hidden].to_b
74
+ update_state(:columns_order, current_columns_order)
72
75
  {}
73
76
  end
74
77
 
@@ -77,7 +80,7 @@ module Netzke
77
80
  query = params[:query]
78
81
 
79
82
  column = columns.detect{ |c| c[:name] == params[:column] }
80
- scope = column.to_options[:scope] || column.to_options[:editor].try(:fetch, :scope)
83
+ scope = column.to_options[:scope] || column.to_options[:editor].try(:fetch, :scope, nil)
81
84
  query = params[:query]
82
85
 
83
86
  {:data => combobox_options_for_column(column, :query => query, :scope => scope, :record_id => params[:id])}
@@ -155,16 +158,36 @@ module Netzke
155
158
  def get_data(*args)
156
159
  params = args.first || {} # params are optional!
157
160
  if !config[:prohibit_read]
158
- records = get_records(params)
159
- {:data => records.map{|r| r.to_array(columns)}, :total => config[:enable_pagination] && records.total_entries}
161
+ {}.tap do |res|
162
+ records = get_records(params)
163
+ res[:data] = records.map{|r| r.to_array(columns(:with_meta => true))}
164
+ res[:total] = records.total_entries if config[:enable_pagination]
165
+
166
+ # provide association values for all records at once
167
+ # assoc_values = get_association_values(records, columns)
168
+ # res[:set_association_values] = assoc_values.literalize_keys if assoc_values.present?
169
+ end
160
170
  else
161
171
  flash :error => "You don't have permissions to read data"
162
- {:feedback => @flash}
172
+ { :feedback => @flash }
163
173
  end
164
174
  end
165
175
 
166
176
  protected
167
177
 
178
+ # Returns all values for association columns, per column, per associated record id, e.g.:
179
+ # {
180
+ # :author__first_name => {1 => "Vladimir", 2 => "Herman"},
181
+ # :author__last_name => {1 => "Nabokov", 2 => "Hesse"}
182
+ # }
183
+ # This is used to display the association by the specified method instead by the foreign key
184
+ # def get_association_values(records, columns)
185
+ # columns.select{ |c| c[:name].index("__") }.each.inject({}) do |r,c|
186
+ # column_values = {}
187
+ # records.each{ |r| column_values[r.value_for_attribute(c)] = r.value_for_attribute(c, true) }
188
+ # r.merge(c[:name] => column_values)
189
+ # end
190
+ # end
168
191
  def get_records(params)
169
192
 
170
193
  # Restore params from component_session if requested
@@ -213,23 +236,6 @@ module Netzke
213
236
  end
214
237
  end
215
238
 
216
- # An ActiveRecord::Relation instance encapsulating all the necessary conditions
217
- def get_relation(params)
218
- # make params coming from Ext grid filters understandable by meta_where
219
- conditions = params[:filter] && convert_filters(params[:filter]) || {}
220
-
221
- relation = data_class.where(conditions)
222
-
223
- if params[:extra_conditions]
224
- extra_conditions = normalize_extra_conditions(ActiveSupport::JSON.decode(params[:extra_conditions]))
225
- relation = relation.extend_with_netzke_conditions(extra_conditions) if params[:extra_conditions]
226
- end
227
-
228
- relation = relation.extend_with(config[:scope]) if config[:scope]
229
-
230
- relation
231
- end
232
-
233
239
  # Override this method to react on each operation that caused changing of data
234
240
  def on_data_changed; end
235
241
 
@@ -277,7 +283,7 @@ module Netzke
277
283
 
278
284
  # try to save
279
285
  # modified_records += 1 if success && record.save
280
- mod_records[id] = record.to_array(columns) if success && record.save
286
+ mod_records[id] = record.to_array(columns(:with_meta => true)) if success && record.save
281
287
  # mod_record_ids << id if success && record.save
282
288
 
283
289
  # flash eventual errors
@@ -316,8 +322,10 @@ module Netzke
316
322
  #
317
323
  # metawhere: :id.gt => 100, :food_name.matches => '%pizza%'
318
324
  def convert_filters(column_filter)
325
+ # these are still JSON-encoded due to the migration to Ext.direct
326
+ column_filter=JSON.parse(column_filter)
319
327
  res = {}
320
- column_filter.each_pair do |k,v|
328
+ column_filter.each do |v|
321
329
  assoc, method = v["field"].split('__')
322
330
  if method
323
331
  assoc = data_class.reflect_on_association(assoc.to_sym)
@@ -326,13 +334,14 @@ module Netzke
326
334
  field = assoc.to_sym
327
335
  end
328
336
 
329
- value = v["data"]["value"]
330
- case v["data"]["type"]
337
+ value = v["value"]
338
+
339
+ case v["type"]
331
340
  when "string"
332
341
  field = field.send :matches
333
342
  value = "%#{value}%"
334
343
  when "numeric", "date"
335
- field = field.send :"#{v['data']['comparison']}"
344
+ field = field.send :"#{v['comparison']}"
336
345
  end
337
346
  res.merge!({field => value})
338
347
  end
@@ -345,6 +354,16 @@ module Netzke
345
354
  end
346
355
  end
347
356
 
357
+ def initial_columns_order
358
+ columns.map do |c|
359
+ {
360
+ :name => c[:name],
361
+ :width => c[:width],
362
+ :hidden => c[:hidden]
363
+ }
364
+ end
365
+ end
366
+
348
367
  # def check_for_positive_result(res)
349
368
  # if res[:set_form_values]
350
369
  # # successful creation
@@ -15,6 +15,9 @@ module Netzke
15
15
  # When it's a Proc, it's passed the model class, and is expected to return an ActiveRecord::Relation, e.g.:
16
16
  #
17
17
  # :scope => { |rel| rel.where(:id.gt => 100).order(:created_at) }
18
+ #
19
+ # == ToDo
20
+ # * Update the number of records after form submit
18
21
  class PagingFormPanel < FormPanel
19
22
 
20
23
  # override
@@ -25,17 +28,75 @@ module Netzke
25
28
  # Pass total records amount and the first record to the JS constructor
26
29
  def js_config
27
30
  super.merge({
28
- :total_records => total_records,
29
- :record => record.to_hash(fields)
31
+ :total_records => total_records
30
32
  })
31
33
  end
32
34
 
33
35
  endpoint :get_data do |params|
34
- record = get_relation.offset(params[:start].to_i).limit(1).first
35
- record_hash = record && record.to_hash(fields).each_pair.inject({}){ |r,(k,v)| r.merge(k.l => v) }
36
- {:records => record_hash && [record_hash] || [], :total => total_records}
36
+ @record = get_relation(params).offset(params[:start].to_i).limit(1).first
37
+ record_hash = @record && js_record_data
38
+ {:records => record_hash && [record_hash] || [], :total => total_records(params)}
39
+ end
40
+
41
+ action :search do
42
+ {
43
+ :text => I18n.t('netzke.basepack.paging_form_panel.actions.search'),
44
+ :tooltip => I18n.t('netzke.basepack.paging_form_panel.actions.search_tooltip'),
45
+ :icon => :find,
46
+ :select => true
47
+ }
37
48
  end
38
49
 
50
+ def configure_bbar(c)
51
+ super
52
+ c[:bbar] << :search.action
53
+ end
54
+
55
+ js_method :on_search, <<-JS
56
+ function(el){
57
+ if (this.searchWindow) {
58
+ this.searchWindow.show();
59
+ } else {
60
+ this.loadComponent({name: 'search_form', callback: function(win){
61
+ this.searchWindow = win;
62
+ var currentConditionsString = this.getStore().baseParams.extra_conditions;
63
+ if (currentConditionsString) {
64
+ win.items.first().getForm().setValues(Ext.decode(currentConditionsString));
65
+ }
66
+
67
+ win.items.first().on('apply', function(){
68
+ win.onSearch();
69
+ return false; // do not propagate the 'apply' event
70
+ }, this);
71
+
72
+ win.on('hide', function(){
73
+ var query = win.getQuery();
74
+ if (win.closeRes == 'search'){
75
+ this.getStore().baseParams.query = Ext.encode(query);
76
+ this.getStore().load();
77
+ }
78
+ el.toggle(query.length > 0); // toggle based on the state
79
+ }, this);
80
+ }, scope: this});
81
+ }
82
+ }
83
+ JS
84
+
85
+ js_method :get_store, <<-JS
86
+ function(){
87
+ return this.store;
88
+ }
89
+ JS
90
+
91
+ js_method :after_render, <<-JS
92
+ function(){
93
+ Netzke.classes.Basepack.PagingFormPanel.superclass.afterRender.call(this);
94
+
95
+ new Ext.LoadMask(this.bwrap, Ext.apply(this.applyMask, {store: this.store}));
96
+ }
97
+ JS
98
+
99
+
39
100
  js_method :init_component, <<-JS
40
101
  function(){
41
102
 
@@ -44,23 +105,20 @@ module Netzke
44
105
  // Otherwise, the things would be simpler, because this.getForm().items would already has all the fields in one place for us
45
106
  this.fieldNames = [];
46
107
  this.extractFields(this.items);
47
- var fieldNames = this.fieldNames;
48
108
 
49
- var store = new Ext.data.JsonStore({
50
- url: this.endpointUrl('get_data'),
109
+ var store = new Ext.data.DirectStore({
110
+ directFn: Netzke.providers[this.id].getData,
51
111
  root: 'records',
52
- fields: fieldNames,
112
+ fields: this.fieldNames.concat('_meta'),
53
113
  data: {records: [this.record], total: this.totalRecords}
54
114
  });
55
115
 
56
- store.on('beforeload', function(){
57
- if (!this.loadMaskCmp) this.loadMaskCmp = new Ext.LoadMask(this.bwrap, this.applyMask);
58
- this.loadMaskCmp.show();
59
- }, this);
60
-
61
116
  store.on('load', function(st, r){
62
- this.setFormValues(r[0].data);
63
- if (this.loadMaskCmp) this.loadMaskCmp.hide();
117
+ if (r.length == 0) {
118
+ this.getForm().reset();
119
+ } else {
120
+ this.setFormValues(r[0].data);
121
+ }
64
122
  }, this);
65
123
 
66
124
  this.bbar = new Ext.PagingToolbar({
@@ -70,21 +128,24 @@ module Netzke
70
128
  items: ["-"].concat(this.bbar || [])
71
129
  });
72
130
 
131
+ this.store = store;
132
+
73
133
  Netzke.classes.Basepack.PagingFormPanel.superclass.initComponent.call(this);
74
134
  }
75
135
  JS
76
136
 
77
- protected
137
+ component :search_form do
138
+ {
139
+ :lazy_loading => true,
140
+ :class_name => "Netzke::Basepack::SearchWindow",
141
+ :model => config[:model]
142
+ }
143
+ end
78
144
 
79
- # Returns ActiveRecord::Relation for the data
80
- def get_relation
81
- relation = data_class.scoped
82
- relation = relation.extend_with(config[:scope]) if config[:scope]
83
- relation
84
- end
145
+ protected
85
146
 
86
- def total_records
87
- @total_records ||= get_relation.count
147
+ def total_records(params = {})
148
+ @total_records ||= get_relation(params).count
88
149
  end
89
150
 
90
151
  end
@@ -0,0 +1,105 @@
1
+ module Netzke
2
+ module Basepack
3
+ class QueryBuilder < Netzke::Base
4
+ js_base_class "Ext.TabPanel"
5
+
6
+ js_property :active_tab, 0
7
+
8
+ js_translate :overwrite_confirm, :overwrite_confirm_title, :delete_confirm, :delete_confirm_title
9
+
10
+ js_mixin :query_builder
11
+
12
+ component :search_panel do
13
+ {
14
+ :class_name => "Netzke::Basepack::SearchPanel",
15
+ :model => config[:model],
16
+ :query => config[:query],
17
+ :auto_scroll => config[:auto_scroll]
18
+ }
19
+ end
20
+
21
+ action :clear_all do
22
+ {
23
+ :text => I18n.t('netzke.basepack.query_builder.actions.clear_all'),
24
+ :tooltip => I18n.t('netzke.basepack.query_builder.actions.clear_all_tooltip'),
25
+ :icon => :cross
26
+ }
27
+ end
28
+
29
+ action :reset do
30
+ {
31
+ :text => I18n.t('netzke.basepack.query_builder.actions.reset'),
32
+ :tooltip => I18n.t('netzke.basepack.query_builder.actions.reset_tooltip'),
33
+ :icon => :application_form
34
+ }
35
+ end
36
+
37
+ action :save_preset do
38
+ {
39
+ :text => I18n.t('netzke.basepack.query_builder.actions.save_preset'),
40
+ :tooltip => I18n.t('netzke.basepack.query_builder.actions.save_preset_tooltip'),
41
+ :icon => :disk
42
+ }
43
+ end
44
+
45
+ action :delete_preset do
46
+ {
47
+ :text => I18n.t('netzke.basepack.query_builder.actions.delete_preset'),
48
+ :tooltip => I18n.t('netzke.basepack.query_builder.actions.delete_preset_tooltip'),
49
+ :icon => :cross
50
+ }
51
+ end
52
+
53
+ action :apply do
54
+ {
55
+ :text => I18n.t('netzke.basepack.query_builder.actions.apply'),
56
+ :tooltip => I18n.t('netzke.basepack.query_builder.actions.apply_tooltip'),
57
+ :icon => :accept
58
+ }
59
+ end
60
+
61
+ def js_config
62
+ super.tap do |s|
63
+ s[:bbar] = (config[:bbar] || []) + [:clear_all.action, :reset.action, "->",
64
+ I18n.t('netzke.basepack.query_builder.presets'),
65
+ {
66
+ :xtype => "combo",
67
+ :triggerAction => "all",
68
+ :value => super[:load_last_preset] && last_preset.try(:fetch, "name"),
69
+ :store => state[:presets].blank? ? [[[], ""]] : state[:presets].map{ |s| [s["query"], s["name"]] },
70
+ :ref => "../presetsCombo",
71
+ :listeners => {:before_select => {
72
+ :fn => "function(combo, record){
73
+ var form = Ext.getCmp('#{global_id}');
74
+ form.buildFormFromQuery(record.data.field1);
75
+ }".l
76
+ }}
77
+ }, :save_preset.action, :delete_preset.action
78
+ ]
79
+ end
80
+ end
81
+
82
+ endpoint :save_preset do |params|
83
+ saved_searches = state[:presets] || []
84
+ existing = saved_searches.detect{ |s| s["name"] == params[:name] }
85
+ query = ActiveSupport::JSON.decode(params[:query])
86
+ if existing
87
+ existing["query"].replace(query)
88
+ else
89
+ saved_searches << {"name" => params[:name], "query" => query}
90
+ end
91
+ update_state(:presets, saved_searches)
92
+ {:feedback => I18n.t('netzke.basepack.query_builder.preset_saved')}
93
+ end
94
+
95
+ endpoint :delete_preset do |params|
96
+ saved_searches = state[:presets]
97
+ saved_searches.delete_if{ |s| s["name"] == params[:name] }
98
+ update_state(:presets, saved_searches)
99
+ {:feedback => I18n.t('netzke.basepack.query_builder.preset_deleted')}
100
+ end
101
+
102
+
103
+ end
104
+ end
105
+ end