Added browser reload support if only config changes have changed. Added support to undo config changes.
This commit is contained in:
parent
f08fcc5e55
commit
d3ec647189
7 changed files with 148 additions and 16 deletions
|
@ -2,6 +2,11 @@
|
||||||
# coffeelint: disable=camel_case_classes
|
# coffeelint: disable=camel_case_classes
|
||||||
class App.UiElement.object_manager_attribute extends App.UiElement.ApplicationUiElement
|
class App.UiElement.object_manager_attribute extends App.UiElement.ApplicationUiElement
|
||||||
@render: (attribute, params = {}) ->
|
@render: (attribute, params = {}) ->
|
||||||
|
|
||||||
|
# if we have already changed settings, use them in edit screen
|
||||||
|
if params.data_option_new && !_.isEmpty(params.data_option_new)
|
||||||
|
params.data_option = params.data_option_new
|
||||||
|
|
||||||
item = $(App.view('object_manager/attribute')(attribute: attribute))
|
item = $(App.view('object_manager/attribute')(attribute: attribute))
|
||||||
|
|
||||||
updateDataMap = (localParams, localAttribute, localAttributes, localClassname, localForm, localA) =>
|
updateDataMap = (localParams, localAttribute, localAttributes, localClassname, localForm, localA) =>
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
<%- @T('Create') %>: <%= item.object %>.<%= item.name %> (<%= item.data_type %>)
|
<%- @T('Create') %>: <%= item.object %>.<%= item.name %> (<%= item.data_type %>)
|
||||||
<% else if item.to_delete is true: %>
|
<% else if item.to_delete is true: %>
|
||||||
<%- @T('Delete') %>: <%= item.object %>.<%= item.name %> (<%= item.data_type %>)
|
<%- @T('Delete') %>: <%= item.object %>.<%= item.name %> (<%= item.data_type %>)
|
||||||
|
<% else if item.to_migrate || item.to_config is true: %>
|
||||||
|
<%- @T('Changed') %>: <%= item.object %>.<%= item.name %> (<%= item.data_type %>)
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -4,6 +4,7 @@ class ObjectManager::Attribute < ApplicationModel
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
store :screens
|
store :screens
|
||||||
store :data_option
|
store :data_option
|
||||||
|
store :data_option_new
|
||||||
|
|
||||||
notify_clients_support
|
notify_clients_support
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ add a new attribute entry for an object
|
||||||
to_migrate: false,
|
to_migrate: false,
|
||||||
to_create: false,
|
to_create: false,
|
||||||
to_delete: false,
|
to_delete: false,
|
||||||
|
to_config: false,
|
||||||
)
|
)
|
||||||
|
|
||||||
preserved name are
|
preserved name are
|
||||||
|
@ -103,6 +105,7 @@ possible types
|
||||||
'aa' => 'aa (comment)',
|
'aa' => 'aa (comment)',
|
||||||
'bb' => 'bb (comment)',
|
'bb' => 'bb (comment)',
|
||||||
},
|
},
|
||||||
|
maxlength: 200,
|
||||||
nulloption: true,
|
nulloption: true,
|
||||||
null: false,
|
null: false,
|
||||||
multiple: false, # currently only "false" supported
|
multiple: false, # currently only "false" supported
|
||||||
|
@ -218,7 +221,24 @@ possible types
|
||||||
data.delete(:to_create)
|
data.delete(:to_create)
|
||||||
data.delete(:to_migrate)
|
data.delete(:to_migrate)
|
||||||
data.delete(:to_delete)
|
data.delete(:to_delete)
|
||||||
|
data.delete(:to_config)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# if data_option has changed, store it for next migration
|
||||||
|
if !force
|
||||||
|
if record[:data_option] != data[:data_option]
|
||||||
|
|
||||||
|
# do we need a database migration?
|
||||||
|
if record[:data_option][:maxlength] && data[:data_option][:maxlength] && record[:data_option][:maxlength].to_s != data[:data_option][:maxlength].to_s
|
||||||
|
data[:to_migrate] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
record[:data_option_new] = data[:data_option]
|
||||||
|
data.delete(:data_option)
|
||||||
|
data[:to_config] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# update attributes
|
# update attributes
|
||||||
data.each {|key, value|
|
data.each {|key, value|
|
||||||
record[key.to_sym] = value
|
record[key.to_sym] = value
|
||||||
|
@ -423,8 +443,11 @@ returns
|
||||||
|
|
||||||
def self.discard_changes
|
def self.discard_changes
|
||||||
ObjectManager::Attribute.where('to_create = ?', true).each(&:destroy)
|
ObjectManager::Attribute.where('to_create = ?', true).each(&:destroy)
|
||||||
ObjectManager::Attribute.where('to_delete = ?', true).each {|attribute|
|
ObjectManager::Attribute.where('to_delete = ? OR to_config = ?', true, true).each {|attribute|
|
||||||
|
attribute.to_migrate = false
|
||||||
attribute.to_delete = false
|
attribute.to_delete = false
|
||||||
|
attribute.to_config = false
|
||||||
|
attribute.data_option_new = {}
|
||||||
attribute.save
|
attribute.save
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -460,7 +483,7 @@ returns
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.migrations
|
def self.migrations
|
||||||
ObjectManager::Attribute.where('to_create = ? OR to_migrate = ? OR to_delete = ?', true, true, true)
|
ObjectManager::Attribute.where('to_create = ? OR to_migrate = ? OR to_delete = ? OR to_config = ?', true, true, true, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
@ -482,7 +505,8 @@ to send no browser reload event, pass false
|
||||||
def self.migration_execute(send_event = true)
|
def self.migration_execute(send_event = true)
|
||||||
|
|
||||||
# check if field already exists
|
# check if field already exists
|
||||||
execute_count = 0
|
execute_db_count = 0
|
||||||
|
execute_config_count = 0
|
||||||
migrations.each {|attribute|
|
migrations.each {|attribute|
|
||||||
model = Kernel.const_get(attribute.object_lookup.name)
|
model = Kernel.const_get(attribute.object_lookup.name)
|
||||||
|
|
||||||
|
@ -492,11 +516,21 @@ to send no browser reload event, pass false
|
||||||
ActiveRecord::Migration.remove_column model.table_name, attribute.name
|
ActiveRecord::Migration.remove_column model.table_name, attribute.name
|
||||||
reset_database_info(model)
|
reset_database_info(model)
|
||||||
end
|
end
|
||||||
execute_count += 1
|
execute_db_count += 1
|
||||||
attribute.destroy
|
attribute.destroy
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# config changes
|
||||||
|
if attribute.to_config
|
||||||
|
execute_config_count += 1
|
||||||
|
attribute.data_option = attribute.data_option_new
|
||||||
|
attribute.data_option_new = {}
|
||||||
|
attribute.to_config = false
|
||||||
|
attribute.save!
|
||||||
|
next if !attribute.to_create && !attribute.to_migrate && !attribute.to_delete
|
||||||
|
end
|
||||||
|
|
||||||
data_type = nil
|
data_type = nil
|
||||||
if attribute.data_type =~ /^input|select|richtext|textarea|checkbox$/
|
if attribute.data_type =~ /^input|select|richtext|textarea|checkbox$/
|
||||||
data_type = :string
|
data_type = :string
|
||||||
|
@ -544,7 +578,7 @@ to send no browser reload event, pass false
|
||||||
attribute.to_migrate = false
|
attribute.to_migrate = false
|
||||||
attribute.save!
|
attribute.save!
|
||||||
reset_database_info(model)
|
reset_database_info(model)
|
||||||
execute_count += 1
|
execute_db_count += 1
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -592,17 +626,21 @@ to send no browser reload event, pass false
|
||||||
attribute.save!
|
attribute.save!
|
||||||
|
|
||||||
reset_database_info(model)
|
reset_database_info(model)
|
||||||
execute_count += 1
|
execute_db_count += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# sent maintenance message to clients
|
# sent maintenance message to clients
|
||||||
if send_event && execute_count != 0
|
if send_event
|
||||||
if ENV['APP_RESTART_CMD']
|
if execute_db_count != 0
|
||||||
AppVersion.set(true, 'restart_auto')
|
if ENV['APP_RESTART_CMD']
|
||||||
sleep 4
|
AppVersion.set(true, 'restart_auto')
|
||||||
Delayed::Job.enqueue(Observer::AppVersionRestartJob.new(ENV['APP_RESTART_CMD']))
|
sleep 4
|
||||||
else
|
Delayed::Job.enqueue(Observer::AppVersionRestartJob.new(ENV['APP_RESTART_CMD']))
|
||||||
AppVersion.set(true, 'restart_manual')
|
else
|
||||||
|
AppVersion.set(true, 'restart_manual')
|
||||||
|
end
|
||||||
|
elsif execute_config_count != 0
|
||||||
|
AppVersion.set(true, 'config_changed')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
|
@ -652,7 +690,12 @@ to send no browser reload event, pass false
|
||||||
# validate data_option
|
# validate data_option
|
||||||
if data_type == 'input'
|
if data_type == 'input'
|
||||||
raise 'Need data_option[:type] param' if !data_option[:type]
|
raise 'Need data_option[:type] param' if !data_option[:type]
|
||||||
raise "Invalid data_option[:type] param '#{data_option[:type]}'" if data_option[:type] !~ /^(text|password|phone|fax|email|url)$/
|
raise "Invalid data_option[:type] param '#{data_option[:type]}'" if data_option[:type] !~ /^(text|password|tel|fax|email|url)$/
|
||||||
|
raise 'Need data_option[:maxlength] param' if !data_option[:maxlength]
|
||||||
|
raise "Invalid data_option[:maxlength] param #{data_option[:maxlength]}" if data_option[:maxlength].to_s !~ /^\d+?$/
|
||||||
|
end
|
||||||
|
|
||||||
|
if data_type == 'richtext'
|
||||||
raise 'Need data_option[:maxlength] param' if !data_option[:maxlength]
|
raise 'Need data_option[:maxlength] param' if !data_option[:maxlength]
|
||||||
raise "Invalid data_option[:maxlength] param #{data_option[:maxlength]}" if data_option[:maxlength].to_s !~ /^\d+?$/
|
raise "Invalid data_option[:maxlength] param #{data_option[:maxlength]}" if data_option[:maxlength].to_s !~ /^\d+?$/
|
||||||
end
|
end
|
||||||
|
@ -667,6 +710,9 @@ to send no browser reload event, pass false
|
||||||
if data_type == 'select' || data_type == 'checkbox'
|
if data_type == 'select' || data_type == 'checkbox'
|
||||||
raise 'Need data_option[:default] param' if !data_option.key?(:default)
|
raise 'Need data_option[:default] param' if !data_option.key?(:default)
|
||||||
raise 'Invalid data_option[:options] or data_option[:relation] param' if data_option[:options].nil? && data_option[:relation].nil?
|
raise 'Invalid data_option[:options] or data_option[:relation] param' if data_option[:options].nil? && data_option[:relation].nil?
|
||||||
|
if !data_option.key?(:maxlength)
|
||||||
|
data_option[:maxlength] = 255
|
||||||
|
end
|
||||||
if !data_option.key?(:nulloption)
|
if !data_option.key?(:nulloption)
|
||||||
data_option[:nulloption] = true
|
data_option[:nulloption] = true
|
||||||
end
|
end
|
||||||
|
|
|
@ -467,12 +467,14 @@ class CreateBase < ActiveRecord::Migration
|
||||||
t.column :display, :string, limit: 200, null: false
|
t.column :display, :string, limit: 200, null: false
|
||||||
t.column :data_type, :string, limit: 100, null: false
|
t.column :data_type, :string, limit: 100, null: false
|
||||||
t.column :data_option, :string, limit: 8000, null: true
|
t.column :data_option, :string, limit: 8000, null: true
|
||||||
|
t.column :data_option_new, :string, limit: 8000, null: true
|
||||||
t.column :editable, :boolean, null: false, default: true
|
t.column :editable, :boolean, null: false, default: true
|
||||||
t.column :active, :boolean, null: false, default: true
|
t.column :active, :boolean, null: false, default: true
|
||||||
t.column :screens, :string, limit: 2000, null: true
|
t.column :screens, :string, limit: 2000, null: true
|
||||||
t.column :to_create, :boolean, null: false, default: false
|
t.column :to_create, :boolean, null: false, default: false
|
||||||
t.column :to_migrate, :boolean, null: false, default: false
|
t.column :to_migrate, :boolean, null: false, default: false
|
||||||
t.column :to_delete, :boolean, null: false, default: false
|
t.column :to_delete, :boolean, null: false, default: false
|
||||||
|
t.column :to_config, :boolean, null: false, default: false
|
||||||
t.column :position, :integer, null: false
|
t.column :position, :integer, null: false
|
||||||
t.column :created_by_id, :integer, null: false
|
t.column :created_by_id, :integer, null: false
|
||||||
t.column :updated_by_id, :integer, null: false
|
t.column :updated_by_id, :integer, null: false
|
||||||
|
|
10
db/migrate/20160529000001_update_object_manager2.rb
Normal file
10
db/migrate/20160529000001_update_object_manager2.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
class UpdateObjectManager2 < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
# return if it's a new setup
|
||||||
|
return if !Setting.find_by(name: 'system_init_done')
|
||||||
|
|
||||||
|
add_column :object_manager_attributes, :to_config, :boolean, null: false, default: false
|
||||||
|
add_column :object_manager_attributes, :data_option_new, :string, limit: 8000, null: true, default: false
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -120,8 +120,11 @@ class AdminObjectManagerTest < TestCase
|
||||||
css: '#content',
|
css: '#content',
|
||||||
value: 'Database Update required',
|
value: 'Database Update required',
|
||||||
)
|
)
|
||||||
click(css: '#content .tab-pane.active table tbody tr:last-child .js-delete')
|
object_manager_attribute_delete(
|
||||||
sleep 4
|
data: {
|
||||||
|
name: 'browser_test1',
|
||||||
|
},
|
||||||
|
)
|
||||||
watch_for(
|
watch_for(
|
||||||
css: '#content',
|
css: '#content',
|
||||||
value: 'Database Update required',
|
value: 'Database Update required',
|
||||||
|
|
|
@ -546,6 +546,70 @@ class ObjectManagerTest < ActiveSupport::TestCase
|
||||||
assert_equal(Time.zone.parse('2016-05-12 00:59:59 UTC'), ticket2.attribute3)
|
assert_equal(Time.zone.parse('2016-05-12 00:59:59 UTC'), ticket2.attribute3)
|
||||||
assert_equal(Date.parse('2016-05-11'), ticket2.attribute4)
|
assert_equal(Date.parse('2016-05-11'), ticket2.attribute4)
|
||||||
|
|
||||||
|
# update data_option null -> to_config
|
||||||
|
attribute1 = ObjectManager::Attribute.add(
|
||||||
|
object: 'Ticket',
|
||||||
|
name: 'attribute1',
|
||||||
|
display: 'Attribute 1',
|
||||||
|
data_type: 'input',
|
||||||
|
data_option: {
|
||||||
|
maxlength: 200,
|
||||||
|
type: 'text',
|
||||||
|
null: false,
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
screens: {},
|
||||||
|
position: 20,
|
||||||
|
created_by_id: 1,
|
||||||
|
updated_by_id: 1,
|
||||||
|
)
|
||||||
|
assert(attribute1)
|
||||||
|
|
||||||
|
assert_equal(true, ObjectManager::Attribute.pending_migration?)
|
||||||
|
assert_equal(0, ObjectManager::Attribute.where(to_migrate: true).count)
|
||||||
|
assert_equal(1, ObjectManager::Attribute.where(to_config: true).count)
|
||||||
|
assert_equal(1, ObjectManager::Attribute.migrations.count)
|
||||||
|
|
||||||
|
# execute migrations
|
||||||
|
assert(ObjectManager::Attribute.migration_execute)
|
||||||
|
|
||||||
|
assert_equal(false, ObjectManager::Attribute.pending_migration?)
|
||||||
|
assert_equal(0, ObjectManager::Attribute.where(to_migrate: true).count)
|
||||||
|
assert_equal(0, ObjectManager::Attribute.where(to_config: true).count)
|
||||||
|
assert_equal(0, ObjectManager::Attribute.migrations.count)
|
||||||
|
|
||||||
|
# update data_option maxlength -> to_config && to_migrate
|
||||||
|
attribute1 = ObjectManager::Attribute.add(
|
||||||
|
object: 'Ticket',
|
||||||
|
name: 'attribute1',
|
||||||
|
display: 'Attribute 1',
|
||||||
|
data_type: 'input',
|
||||||
|
data_option: {
|
||||||
|
maxlength: 250,
|
||||||
|
type: 'text',
|
||||||
|
null: false,
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
screens: {},
|
||||||
|
position: 20,
|
||||||
|
created_by_id: 1,
|
||||||
|
updated_by_id: 1,
|
||||||
|
)
|
||||||
|
assert(attribute1)
|
||||||
|
|
||||||
|
assert_equal(true, ObjectManager::Attribute.pending_migration?)
|
||||||
|
assert_equal(1, ObjectManager::Attribute.where(to_migrate: true).count)
|
||||||
|
assert_equal(1, ObjectManager::Attribute.where(to_config: true).count)
|
||||||
|
assert_equal(1, ObjectManager::Attribute.migrations.count)
|
||||||
|
|
||||||
|
# execute migrations
|
||||||
|
assert(ObjectManager::Attribute.migration_execute)
|
||||||
|
|
||||||
|
assert_equal(false, ObjectManager::Attribute.pending_migration?)
|
||||||
|
assert_equal(0, ObjectManager::Attribute.where(to_migrate: true).count)
|
||||||
|
assert_equal(0, ObjectManager::Attribute.where(to_config: true).count)
|
||||||
|
assert_equal(0, ObjectManager::Attribute.migrations.count)
|
||||||
|
|
||||||
# remove attribute
|
# remove attribute
|
||||||
ObjectManager::Attribute.remove(
|
ObjectManager::Attribute.remove(
|
||||||
object: 'Ticket',
|
object: 'Ticket',
|
||||||
|
|
Loading…
Reference in a new issue