marty 0.5.15 → 0.5.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +27 -0
- data/.rspec +3 -0
- data/.travis.yml +23 -0
- data/Gemfile +23 -0
- data/INDEPENDENCE_ISSUES.md +23 -0
- data/app/assets/images/marty/.gitkeep +0 -0
- data/app/components/marty/report_form.rb +9 -4
- data/gemini_deprecations.md +6 -0
- data/lib/marty/data_change.rb +99 -0
- data/lib/marty/data_conversion.rb +11 -3
- data/lib/marty/data_exporter.rb +9 -0
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +35 -0
- data/script/rails +8 -0
- data/spec/controllers/application_controller_spec.rb +52 -0
- data/spec/controllers/job_controller_spec.rb +226 -0
- data/spec/controllers/rpc_controller_spec.rb +379 -0
- data/spec/controllers/rpc_import_spec.rb +45 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/components_controller.rb +7 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/gemini/amortization_type.rb +5 -0
- data/spec/dummy/app/models/gemini/bud_category.rb +7 -0
- data/spec/dummy/app/models/gemini/entity.rb +2 -0
- data/spec/dummy/app/models/gemini/extras/data_import.rb +5 -0
- data/spec/dummy/app/models/gemini/extras/settlement_import.rb +28 -0
- data/spec/dummy/app/models/gemini/fannie_bup.rb +29 -0
- data/spec/dummy/app/models/gemini/grouping.rb +8 -0
- data/spec/dummy/app/models/gemini/grouping_head_version.rb +14 -0
- data/spec/dummy/app/models/gemini/head.rb +7 -0
- data/spec/dummy/app/models/gemini/head_version.rb +14 -0
- data/spec/dummy/app/models/gemini/helper.rb +44 -0
- data/spec/dummy/app/models/gemini/loan_program.rb +11 -0
- data/spec/dummy/app/models/gemini/mortgage_type.rb +5 -0
- data/spec/dummy/app/models/gemini/simple.rb +6 -0
- data/spec/dummy/app/models/gemini/streamline_type.rb +16 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +82 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml.example +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +35 -0
- data/spec/dummy/config/environments/production.rb +69 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/delayed_job.rb +5 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +12 -0
- data/spec/dummy/db/migrate/20140801000000_create_groupings.rb +11 -0
- data/spec/dummy/db/migrate/20150406171536_create_categories.rb +27 -0
- data/spec/dummy/db/migrate/20150408200916_create_loan_programs.rb +26 -0
- data/spec/dummy/db/migrate/20150408201429_create_types.rb +21 -0
- data/spec/dummy/db/migrate/20150420000001_create_heads.rb +14 -0
- data/spec/dummy/db/migrate/20150420000002_create_head_versions.rb +15 -0
- data/spec/dummy/db/migrate/20150420000003_create_grouping_head_versions.rb +12 -0
- data/spec/dummy/db/migrate/20151023000001_create_simple.rb +12 -0
- data/spec/dummy/db/seeds.rb +8 -0
- data/spec/dummy/delorean/blame_report.dl +171 -0
- data/spec/dummy/delorean/data_report.dl +105 -0
- data/spec/dummy/delorean/fields.dl +52 -0
- data/spec/dummy/delorean/styles.dl +134 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/class_list.rb +3 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/icons/READ.txt +3 -0
- data/spec/dummy/public/icons/application_cascade.png +0 -0
- data/spec/dummy/public/icons/application_delete.png +0 -0
- data/spec/dummy/public/icons/application_put.png +0 -0
- data/spec/dummy/public/icons/application_view_detail.png +0 -0
- data/spec/dummy/public/icons/arrow_in.png +0 -0
- data/spec/dummy/public/icons/arrow_refresh.png +0 -0
- data/spec/dummy/public/icons/database_save.png +0 -0
- data/spec/dummy/public/icons/door_in.png +0 -0
- data/spec/dummy/public/icons/door_out.png +0 -0
- data/spec/dummy/public/icons/group.png +0 -0
- data/spec/dummy/public/icons/page_lightning.png +0 -0
- data/spec/dummy/public/icons/printer.png +0 -0
- data/spec/dummy/public/icons/report_disk.png +0 -0
- data/spec/dummy/public/icons/report_go.png +0 -0
- data/spec/dummy/public/icons/report_magnify.png +0 -0
- data/spec/dummy/public/icons/script.png +0 -0
- data/spec/dummy/public/icons/script_add.png +0 -0
- data/spec/dummy/public/icons/script_go.png +0 -0
- data/spec/dummy/public/icons/script_key.png +0 -0
- data/spec/dummy/public/icons/table_go.png +0 -0
- data/spec/dummy/public/icons/time.png +0 -0
- data/spec/dummy/public/icons/time_add.png +0 -0
- data/spec/dummy/public/icons/time_go.png +0 -0
- data/spec/dummy/public/icons/timeline_marker.png +0 -0
- data/spec/dummy/public/icons/user_add.png +0 -0
- data/spec/dummy/public/icons/user_delete.png +0 -0
- data/spec/dummy/public/icons/user_edit.png +0 -0
- data/spec/dummy/public/icons/wrench.png +0 -0
- data/spec/dummy/script/delayed_job +6 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/features/javascripts/job_dashboard_live_search.js.coffee +8 -0
- data/spec/features/javascripts/login.js.coffee +8 -0
- data/spec/features/jobs_dashboard_netzke_spec.rb +24 -0
- data/spec/features/jobs_dashboard_spec.rb +49 -0
- data/spec/fixtures/scripts/load_tests/script1.dl +2 -0
- data/spec/fixtures/scripts/load_tests/script2.dl +2 -0
- data/spec/job_helper.rb +102 -0
- data/spec/lib/data_exporter_spec.rb +71 -0
- data/spec/lib/data_importer_spec.rb +461 -0
- data/spec/lib/xl_spec.rb +198 -0
- data/spec/lib/xl_styles_spec.rb +115 -0
- data/spec/models/api_auth_spec.rb +187 -0
- data/spec/models/posting_spec.rb +107 -0
- data/spec/models/promise_spec.rb +65 -0
- data/spec/models/script_spec.rb +187 -0
- data/spec/models/user_spec.rb +68 -0
- data/spec/requests/routes_spec.rb +12 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/clean_db_helpers.rb +18 -0
- data/spec/support/delayed_job_helpers.rb +12 -0
- data/spec/support/user_helpers.rb +12 -0
- metadata +139 -89
- data/app/components/marty/auth_app.rb~ +0 -51
- data/app/components/marty/auth_app/javascripts/auth_app.js~ +0 -91
- data/app/components/marty/cm_form_panel.rb~ +0 -5
- data/app/components/marty/cm_grid_panel.rb~ +0 -35
- data/app/components/marty/data_import_view.rb~ +0 -142
- data/app/components/marty/extras/layout.rb~ +0 -46
- data/app/components/marty/live_search_grid_panel.rb~ +0 -49
- data/app/components/marty/main_auth_app.rb~ +0 -238
- data/app/components/marty/mcfly_grid_panel.rb~ +0 -80
- data/app/components/marty/new_posting_form.rb~ +0 -46
- data/app/components/marty/new_posting_window.rb~ +0 -21
- data/app/components/marty/pivot_grid.rb +0 -52
- data/app/components/marty/pivot_grid/endpoints.rb +0 -45
- data/app/components/marty/pivot_grid/javascripts/extensions.js +0 -150
- data/app/components/marty/pivot_grid/javascripts/pivot_grid.js +0 -86
- data/app/components/marty/pivot_grid/services.rb +0 -44
- data/app/components/marty/posting_grid.rb~ +0 -140
- data/app/components/marty/promise_view.rb~ +0 -157
- data/app/components/marty/promise_view/stylesheets/promise_view.css~ +0 -15
- data/app/components/marty/report_form.rb~ +0 -217
- data/app/components/marty/report_select.rb~ +0 -133
- data/app/components/marty/reporting.rb~ +0 -39
- data/app/components/marty/script_detail.rb~ +0 -430
- data/app/components/marty/script_form.rb~ +0 -233
- data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js~ +0 -909
- data/app/components/marty/script_grid.rb~ +0 -99
- data/app/components/marty/script_tester.rb~ +0 -213
- data/app/components/marty/scripting.rb~ +0 -124
- data/app/components/marty/select_report.rb~ +0 -143
- data/app/components/marty/simple_app.rb~ +0 -101
- data/app/components/marty/tag_grid.rb~ +0 -89
- data/app/components/marty/tree_panel.rb~ +0 -256
- data/app/components/marty/tree_panel/javascripts/tree_panel.js~ +0 -317
- data/app/components/marty/user_pivot.rb +0 -128
- data/app/components/marty/user_view.rb~ +0 -188
- data/app/controllers/marty/application_controller.rb~ +0 -133
- data/app/controllers/marty/components_controller.rb~ +0 -37
- data/app/controllers/marty/job_controller.rb~ +0 -28
- data/app/controllers/marty/rpc_controller.rb~ +0 -61
- data/app/helpers/marty/script_set.rb~ +0 -59
- data/app/models/marty/api_auth.rb~ +0 -48
- data/app/models/marty/data_change.rb~ +0 -141
- data/app/models/marty/enum.rb~ +0 -16
- data/app/models/marty/import_type.rb~ +0 -48
- data/app/models/marty/poop.rb~ +0 -169
- data/app/models/marty/posting.rb~ +0 -86
- data/app/models/marty/posting_type.rb~ +0 -21
- data/app/models/marty/promise.rb~ +0 -196
- data/app/models/marty/role.rb~ +0 -10
- data/app/models/marty/script.rb~ +0 -62
- data/app/models/marty/tag.rb~ +0 -91
- data/app/models/marty/user.rb~ +0 -148
- data/app/models/marty/user_role.rb~ +0 -13
- data/app/views/layouts/marty/application.html.erb~ +0 -11
- data/config/routes.rb~ +0 -10
- data/db/migrate/019_create_marty_postings.rb~ +0 -19
- data/db/migrate/095_create_marty_tags.rb~ +0 -19
- data/lib/marty.rb~ +0 -13
- data/lib/marty/content_handler.rb~ +0 -93
- data/lib/marty/data_exporter.rb~ +0 -137
- data/lib/marty/data_importer.rb~ +0 -114
- data/lib/marty/data_row_processor.rb~ +0 -206
- data/lib/marty/drop_folder_hook.rb~ +0 -17
- data/lib/marty/folder_hook.rb~ +0 -9
- data/lib/marty/lazy_column_loader.rb~ +0 -47
- data/lib/marty/mcfly_query.rb~ +0 -188
- data/lib/marty/migrations.rb~ +0 -65
- data/lib/marty/monkey.rb~ +0 -160
- data/lib/marty/permissions.rb~ +0 -69
- data/lib/marty/promise.rb~ +0 -41
- data/lib/marty/promise_job.rb~ +0 -121
- data/lib/marty/promise_proxy.rb~ +0 -69
- data/lib/marty/util.rb~ +0 -80
- data/lib/marty/version.rb~ +0 -3
- data/lib/marty/xl.rb~ +0 -526
- data/lib/pyxll/README.txt~ +0 -16
- data/lib/pyxll/gemini.py~ +0 -110
- data/lib/pyxll/pyxll.cfg~ +0 -12
@@ -1,101 +0,0 @@
|
|
1
|
-
module Netzke
|
2
|
-
module Basepack
|
3
|
-
# Basis for a Ext.container.Viewport-based one-page application.
|
4
|
-
#
|
5
|
-
# == Features:
|
6
|
-
# * dynamic loading of components
|
7
|
-
# * browser history support (press the "Back"-button to go to the previously loaded component)
|
8
|
-
# * AJAX activity indicator
|
9
|
-
#
|
10
|
-
# == Extending SimpleApp
|
11
|
-
# You may want to extend SimpleApp to provide a custom layout. Make sure you create three regions with predefined itemId's that will be used by SimpleApp. You can use the following methods defined by SimpleApp: main_panel_config, status_bar_config, and menu_bar_config, e.g.:
|
12
|
-
#
|
13
|
-
# class MySimpleApp < Netzke::Basepack::SimpleApp
|
14
|
-
#
|
15
|
-
# def configuration
|
16
|
-
# super.merge(
|
17
|
-
# :items => [my_custom_navigation_config, main_panel_config, menu_bar_config, status_bar_config]
|
18
|
-
# )
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# def my_custom_navigation_config
|
22
|
-
# {
|
23
|
-
# :item_id => 'navigation',
|
24
|
-
# :region => :east,
|
25
|
-
# :width => 200
|
26
|
-
# }
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# ...
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# The JS side of the component will have those regions referenced as this.mainPanel, this.statusBar, and this.menuBar.
|
33
|
-
class SimpleApp < Base
|
34
|
-
js_configure do |c|
|
35
|
-
c.extend = "Ext.container.Viewport"
|
36
|
-
c.layout = :border
|
37
|
-
c.require Netzke::Core.ext_path.join("examples", "ux/statusbar/StatusBar.js"), :statusbar_ext
|
38
|
-
c.mixin
|
39
|
-
end
|
40
|
-
|
41
|
-
def configure(c)
|
42
|
-
super
|
43
|
-
c.items = [main_panel_config, menu_bar_config, status_bar_config]
|
44
|
-
end
|
45
|
-
|
46
|
-
# In Ext 4.1 calling `render` on a viewport causes an error
|
47
|
-
def js_component_render
|
48
|
-
""
|
49
|
-
end
|
50
|
-
|
51
|
-
# Override for custom menu
|
52
|
-
def menu
|
53
|
-
[]
|
54
|
-
end
|
55
|
-
|
56
|
-
# Config for the main panel, which will contain dynamically loaded components.
|
57
|
-
def main_panel_config(overrides = {})
|
58
|
-
{
|
59
|
-
:itemId => 'main_panel',
|
60
|
-
:region => 'center',
|
61
|
-
:layout => 'fit'
|
62
|
-
}.merge(overrides)
|
63
|
-
end
|
64
|
-
|
65
|
-
# Config for the status bar
|
66
|
-
def status_bar_config(overrides = {})
|
67
|
-
{
|
68
|
-
:itemId => 'status_bar',
|
69
|
-
:xtype => 'statusbar',
|
70
|
-
:region => 'south',
|
71
|
-
:height => 22,
|
72
|
-
:statusAlign => 'right',
|
73
|
-
:busyText => 'Busy...',
|
74
|
-
:default_text => "Ready",
|
75
|
-
:default_icon_cls => ""
|
76
|
-
}.merge(overrides)
|
77
|
-
end
|
78
|
-
|
79
|
-
# Config for the menu bar
|
80
|
-
def menu_bar_config(overrides = {})
|
81
|
-
{
|
82
|
-
:itemId => 'menu_bar',
|
83
|
-
:xtype => 'toolbar',
|
84
|
-
:region => 'north',
|
85
|
-
:height => 28,
|
86
|
-
:items => menu
|
87
|
-
}.merge(overrides)
|
88
|
-
end
|
89
|
-
|
90
|
-
# Html required for Ext.History to work
|
91
|
-
def js_component_html
|
92
|
-
super << %Q{
|
93
|
-
<form id="history-form" class="x-hidden">
|
94
|
-
<input type="hidden" id="x-history-field" />
|
95
|
-
<iframe id="x-history-frame"></iframe>
|
96
|
-
</form>
|
97
|
-
}
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
class Marty::TagGrid < Marty::CmGridPanel
|
2
|
-
has_marty_permissions read: :any,
|
3
|
-
create: :dev
|
4
|
-
|
5
|
-
def configure(c)
|
6
|
-
super
|
7
|
-
|
8
|
-
c.header = false
|
9
|
-
c.model = "Marty::Tag"
|
10
|
-
c.columns ||= [:name, :created_dt, :user__name, :comment]
|
11
|
-
c.data_store.sorters = {
|
12
|
-
property: :created_dt,
|
13
|
-
direction: 'DESC',
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
js_configure do |c|
|
18
|
-
c.init_component = <<-JS
|
19
|
-
function() {
|
20
|
-
this.callParent();
|
21
|
-
// Set single selection mode. FIXME: can this be done on config?
|
22
|
-
this.getSelectionModel().setSelectionMode('SINGLE');
|
23
|
-
}
|
24
|
-
JS
|
25
|
-
end
|
26
|
-
|
27
|
-
endpoint :add_window__add_form__netzke_submit do |params, this|
|
28
|
-
data = ActiveSupport::JSON.decode(params[:data])
|
29
|
-
|
30
|
-
return this.netzke_feedback("Permission Denied") if
|
31
|
-
config[:prohibit_create]
|
32
|
-
|
33
|
-
# FIXME: disallow tag creation when no script has been modified?
|
34
|
-
|
35
|
-
tag = Marty::Tag.do_create(nil, data["comment"])
|
36
|
-
|
37
|
-
if tag.valid?
|
38
|
-
this.success = true
|
39
|
-
this.on_submit_success
|
40
|
-
return
|
41
|
-
end
|
42
|
-
|
43
|
-
data_adapter.errors_array(tag).each do |error|
|
44
|
-
flash :error => error
|
45
|
-
end
|
46
|
-
|
47
|
-
this.netzke_feedback(@flash)
|
48
|
-
end
|
49
|
-
|
50
|
-
action :add_in_form do |a|
|
51
|
-
a.text = "New Tag"
|
52
|
-
a.tooltip = "New Tag"
|
53
|
-
a.icon = :time_add
|
54
|
-
a.disabled = config[:prohibit_create]
|
55
|
-
end
|
56
|
-
|
57
|
-
def default_bbar
|
58
|
-
[:add_in_form]
|
59
|
-
end
|
60
|
-
|
61
|
-
def default_context_menu
|
62
|
-
[]
|
63
|
-
end
|
64
|
-
|
65
|
-
def default_fields_for_forms
|
66
|
-
[:comment]
|
67
|
-
end
|
68
|
-
|
69
|
-
column :name do |c|
|
70
|
-
end
|
71
|
-
|
72
|
-
column :created_dt do |c|
|
73
|
-
c.text = "Date/Time"
|
74
|
-
c.format = "Y-m-d H:i"
|
75
|
-
c.hidden = true
|
76
|
-
end
|
77
|
-
|
78
|
-
column :user__name do |c|
|
79
|
-
c.width = 100
|
80
|
-
end
|
81
|
-
|
82
|
-
column :comment do |c|
|
83
|
-
c.width = 100
|
84
|
-
c.flex = 1
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
TagGrid = Marty::TagGrid
|
@@ -1,256 +0,0 @@
|
|
1
|
-
# Ext.tree.TreePanel-based component
|
2
|
-
#
|
3
|
-
# ATTRIBUTION: this code is based on the netzke-extension module found at:
|
4
|
-
# https://github.com/phgrey/netzke-extension
|
5
|
-
# TODO: Add documentation for usage
|
6
|
-
|
7
|
-
class Marty::TreePanel < Netzke::Base
|
8
|
-
include ::Netzke::Basepack::DataAccessor
|
9
|
-
include ::Netzke::Basepack::Columns
|
10
|
-
|
11
|
-
self.default_instance_config = {
|
12
|
-
indicate_leafs: true,
|
13
|
-
auto_scroll: false,
|
14
|
-
root_visible: false,
|
15
|
-
load_inline_data: false,
|
16
|
-
enable_pagination: false,
|
17
|
-
rows_per_page: 30,
|
18
|
-
treecolumn: 'tree' # default name for tree column
|
19
|
-
}
|
20
|
-
|
21
|
-
def js_configure(c) #:nodoc:
|
22
|
-
super
|
23
|
-
c.bbar = bbar
|
24
|
-
end
|
25
|
-
|
26
|
-
js_configure do |c|
|
27
|
-
c.extend = "Ext.tree.TreePanel"
|
28
|
-
c.mixin
|
29
|
-
c.root_visible = false
|
30
|
-
end
|
31
|
-
|
32
|
-
# Configure dynamic JS properties for instantiation
|
33
|
-
def js_config
|
34
|
-
super.tap do |c|
|
35
|
-
# Hand over inline data to the js config hash
|
36
|
-
c[:inline_data] = get_data if config[:load_inline_data]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def configure(c) #:nodoc:
|
41
|
-
super
|
42
|
-
c.title ||= self.class.js_config.properties[:title] ||
|
43
|
-
data_class.name.pluralize
|
44
|
-
c.columns = final_columns(with_meta: true)
|
45
|
-
|
46
|
-
# Set it to the primary key if not given and camelize it Setting
|
47
|
-
# it to anything else than the primary key is especially useful
|
48
|
-
# when instances of different class are shown in one tree because
|
49
|
-
# the primary key MUST be unique!
|
50
|
-
c.pri = (c.pri || data_class.primary_key).to_s.camelize(:lower)
|
51
|
-
|
52
|
-
# Add extra fields for a tree: A method ':name(r)' is called for
|
53
|
-
# every record to retrieve the value
|
54
|
-
c.extra_fields ||= []
|
55
|
-
|
56
|
-
# This will call leaf?(r) for every record
|
57
|
-
c.extra_fields << {name: 'leaf', type: 'boolean'}
|
58
|
-
|
59
|
-
# This will call expanded?(r) for every record
|
60
|
-
c.extra_fields << {name: 'expanded', type: 'boolean'}
|
61
|
-
|
62
|
-
# only if the node id property is different from the data class'
|
63
|
-
# primary key, we need to add and extra field
|
64
|
-
c.extra_fields << {name: c.pri.to_s.camelize(:lower), type: 'string'} if
|
65
|
-
c.pri != data_class.primary_key
|
66
|
-
end
|
67
|
-
|
68
|
-
def config
|
69
|
-
@config ||= ActiveSupport::OrderedOptions.new.tap do |c|
|
70
|
-
# extend with data_store convenient config object
|
71
|
-
c.data_store = ActiveSupport::OrderedOptions.new
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def bbar
|
76
|
-
config[:bbar]
|
77
|
-
end
|
78
|
-
|
79
|
-
# Sets the xtype to 'treecolumn' for the column with name equal to
|
80
|
-
# the :treecolumn value of the config
|
81
|
-
def set_default_xtype(c)
|
82
|
-
c[:xtype] = 'treecolumn' if c[:name].to_s == config[:treecolumn].to_s
|
83
|
-
end
|
84
|
-
|
85
|
-
# Set data_index -- The name of the field configuration of the Ext
|
86
|
-
# JS model will be set to this value This is neccessary since the
|
87
|
-
# data is serialized as a hash (with camelized keys) so the
|
88
|
-
# data_index must also be camelized
|
89
|
-
def set_default_data_index(c)
|
90
|
-
c[:data_index] = c[:name].camelize(:lower)
|
91
|
-
end
|
92
|
-
|
93
|
-
# Call super and then set the data_index
|
94
|
-
def augment_column_config(c)
|
95
|
-
super
|
96
|
-
set_default_data_index(c)
|
97
|
-
set_default_xtype c
|
98
|
-
end
|
99
|
-
|
100
|
-
# @!method get_data_endpoint
|
101
|
-
#
|
102
|
-
# Returns something like:
|
103
|
-
# [
|
104
|
-
# { 'id'=> 1, 'text'=> 'A folder Node', 'leaf'=> false },
|
105
|
-
# { 'id'=> 2, 'text'=> 'A leaf Node', 'leaf'=> true }
|
106
|
-
# ]
|
107
|
-
#
|
108
|
-
# @param [Hash] params
|
109
|
-
endpoint :get_data do |params, this|
|
110
|
-
this.merge! get_data(params)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Method that is called by the get_data endpoint
|
114
|
-
# Calls the get_children method and returns the serialized records
|
115
|
-
#
|
116
|
-
# @param [] *args takes any arguments
|
117
|
-
# @return [Hash] all the serialized data
|
118
|
-
def get_data(*args)
|
119
|
-
params = args.first || {} # params are optional!
|
120
|
-
|
121
|
-
sortp = params["sort"]
|
122
|
-
|
123
|
-
# Giant hack to fix property field used in sort. Not sure why
|
124
|
-
# this is coming in camelized.
|
125
|
-
if sortp.is_a?(Array)
|
126
|
-
sortp.each { |h|
|
127
|
-
h["property"] = h["property"].underscore if
|
128
|
-
h.is_a?(Hash) && h["property"]
|
129
|
-
}
|
130
|
-
end
|
131
|
-
|
132
|
-
if !config[:prohibit_read]
|
133
|
-
{}.tap do |res|
|
134
|
-
# set children to an instance variable in order to access them later
|
135
|
-
@records = get_children(params)
|
136
|
-
|
137
|
-
# Serialize children
|
138
|
-
res[:data] = serialize_data(@records)
|
139
|
-
|
140
|
-
res[:total] = count_records(params) if
|
141
|
-
config[:enable_pagination] &&
|
142
|
-
(params[:id].nil? || params[:id] == 'root')
|
143
|
-
end
|
144
|
-
else
|
145
|
-
flash :error => "You don't have permissions to read data"
|
146
|
-
{ :netzke_feedback => @flash }
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# Serializes an array of objects
|
151
|
-
#
|
152
|
-
# @param [Array] records
|
153
|
-
# @return [Array] the serialized data
|
154
|
-
def serialize_data(records)
|
155
|
-
records.map { |r|
|
156
|
-
data_adapter.record_to_hash(r, final_columns(:with_meta => true)).tap { |h|
|
157
|
-
|
158
|
-
config[:extra_fields].each do |f|
|
159
|
-
name = f[:name].underscore.to_sym
|
160
|
-
h[name] = send("#{name}#{f[:type] == 'boolean' ? '?' : ''}", r)
|
161
|
-
end
|
162
|
-
|
163
|
-
inline_children = get_inline_children(r)
|
164
|
-
h[:data] = serialize_data(inline_children) unless inline_children.nil?
|
165
|
-
h
|
166
|
-
}
|
167
|
-
}
|
168
|
-
end
|
169
|
-
|
170
|
-
# Retrieves all children for a node
|
171
|
-
# Note: It's recommended to override this method
|
172
|
-
#
|
173
|
-
# @param [Hash] params
|
174
|
-
# @return [Array] array of records
|
175
|
-
def get_children(params)
|
176
|
-
scope_data_class(params) do
|
177
|
-
params[:limit] = config[:rows_per_page] if
|
178
|
-
config[:enable_pagination] && (params[:id].nil? || params[:id] == 'root')
|
179
|
-
params[:scope] = config[:scope]
|
180
|
-
data_adapter.get_records(params, final_columns)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
# Scopes the data class depending on the config of the parent_key and the node
|
185
|
-
#
|
186
|
-
# @param [Hash] params
|
187
|
-
def scope_data_class(params, &block)
|
188
|
-
if config[:parent_key]
|
189
|
-
# The value of the pri property of the expanded node is passed
|
190
|
-
# as params[:id] ('root' for the root collection)
|
191
|
-
if params[:id].nil? || params[:id] == 'root'
|
192
|
-
data_class.where(config[:parent_key] => nil).scoping do
|
193
|
-
yield
|
194
|
-
end
|
195
|
-
else
|
196
|
-
data_class.where(config[:parent_key] => params[:id]).scoping do
|
197
|
-
yield
|
198
|
-
end
|
199
|
-
end
|
200
|
-
else
|
201
|
-
yield
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
# Counts the total records
|
206
|
-
#
|
207
|
-
# @param [Hash] params
|
208
|
-
# @return [Fixnum] The number of records
|
209
|
-
def count_records(params)
|
210
|
-
scope_data_class(params) do
|
211
|
-
params[:scope] = config[:scope]
|
212
|
-
data_adapter.count_records(params, final_columns)
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
# Should return all children of the record that should also be
|
217
|
-
# serialized in the current request
|
218
|
-
# Note: It's recommended to override this method
|
219
|
-
#
|
220
|
-
# @param [Object] r The record for which the inline children should be loaded
|
221
|
-
# @return [NilClass, Array] If nil is returned, the tree doesn't
|
222
|
-
# know anything about any children, so opening the node will cause
|
223
|
-
# another request. If an empty array is returned, the tree assumes
|
224
|
-
# that there are no children available for this node (and thus you
|
225
|
-
# can't open it!)
|
226
|
-
def get_inline_children(r)
|
227
|
-
nil
|
228
|
-
end
|
229
|
-
|
230
|
-
# Is the record a leaf or not?
|
231
|
-
# Note: It's recommended to override this method
|
232
|
-
#
|
233
|
-
# @param [Object] r
|
234
|
-
# @return [Boolean] Whether the node is a leaf or not
|
235
|
-
def leaf?(r)
|
236
|
-
r.children.empty?
|
237
|
-
end
|
238
|
-
|
239
|
-
# Is the record a expanded or not?
|
240
|
-
# Note: It's recommended to override this method
|
241
|
-
#
|
242
|
-
# @param [Object] r
|
243
|
-
# @return [Boolean] Whether the node is expanded or not
|
244
|
-
def expanded?(r)
|
245
|
-
false
|
246
|
-
end
|
247
|
-
|
248
|
-
# Is the record a leaf or not?
|
249
|
-
# Note: It's recommended to override this method
|
250
|
-
#
|
251
|
-
# @param [Object] r
|
252
|
-
# @return [Boolean] Whether the node is a leaf or not
|
253
|
-
def node_id(r)
|
254
|
-
r.send(data_class.primary_key)
|
255
|
-
end
|
256
|
-
end
|
@@ -1,317 +0,0 @@
|
|
1
|
-
// This is a hacked up version of 0.8.4 grid.js to work with
|
2
|
-
// TreePanel. FIXME: perhaps we can patch up grid.js dynamically
|
3
|
-
// rather than copying all the code?
|
4
|
-
{
|
5
|
-
trackMouseOver: true,
|
6
|
-
loadMask: true,
|
7
|
-
|
8
|
-
componentLoadMask: {msg: "Loading..."},
|
9
|
-
deleteMaskMsg: "Deleting...",
|
10
|
-
|
11
|
-
initComponent: function(){
|
12
|
-
var metaColumn;
|
13
|
-
var fields = this.extraFields; // field configs for the underlying data model
|
14
|
-
|
15
|
-
this.plugins = this.plugins || [];
|
16
|
-
this.features = this.features || [];
|
17
|
-
|
18
|
-
// Run through columns and set up different configuration for each
|
19
|
-
Ext.each(this.columns, function(c, i){
|
20
|
-
|
21
|
-
this.normalizeRenderer(c);
|
22
|
-
|
23
|
-
// Build the field configuration for this column
|
24
|
-
var fieldConfig = {name: c.dataIndex, defaultValue: c.defaultValue, useNull: true};
|
25
|
-
|
26
|
-
if (c.name !== 'meta') fieldConfig.type = this.fieldTypeForAttrType(c.attrType); // field type (grid editors need this to function well)
|
27
|
-
|
28
|
-
if (c.attrType == 'datetime') {
|
29
|
-
fieldConfig.dateFormat = 'Y-m-d H:i:s'; // set the format in which we receive datetime from the server (so that the model can parse it)
|
30
|
-
|
31
|
-
// While for 'date' columns the renderer is set up automatically (through using column's xtype), there's no appropriate xtype for our custom datetime column.
|
32
|
-
// Thus, we need to set the renderer manually.
|
33
|
-
// NOTE: for Ext there's no distinction b/w date and datetime; date fields can include time.
|
34
|
-
if (!c.renderer) {
|
35
|
-
// format in which the data will be rendered; if c.format is nil, Ext.Date.defaultFormat extended with time will be used
|
36
|
-
c.renderer = Ext.util.Format.dateRenderer(c.format || Ext.Date.defaultFormat + " H:i:s");
|
37
|
-
}
|
38
|
-
};
|
39
|
-
|
40
|
-
// because checkcolumn doesn't care about editor (not) being set, we need to explicitely set readOnly here
|
41
|
-
if (c.xtype == 'checkcolumn' && !c.editor) {
|
42
|
-
c.readOnly = true;
|
43
|
-
}
|
44
|
-
|
45
|
-
fields.push(fieldConfig);
|
46
|
-
|
47
|
-
// We will not use meta columns as actual columns (not even hidden) - only to create the records
|
48
|
-
if (c.meta) {
|
49
|
-
metaColumn = c;
|
50
|
-
return;
|
51
|
-
}
|
52
|
-
|
53
|
-
// Set rendeder for association columns (the one displaying associations by the specified method instead of id)
|
54
|
-
if (c.assoc) {
|
55
|
-
// Editor for association column
|
56
|
-
c.editor = Ext.apply({
|
57
|
-
parentId: this.id,
|
58
|
-
name: c.name,
|
59
|
-
selectOnFocus: true // ?
|
60
|
-
}, c.editor);
|
61
|
-
|
62
|
-
// Renderer for association column
|
63
|
-
this.normalizeAssociationRenderer(c);
|
64
|
-
}
|
65
|
-
|
66
|
-
if (c.editor) {
|
67
|
-
Ext.applyIf(c.editor, {selectOnFocus: true});
|
68
|
-
}
|
69
|
-
|
70
|
-
// Setting the default filter type
|
71
|
-
if (c.filterable && !c.filter) {
|
72
|
-
c.filter = {type: this.fieldTypeForAttrType(c.attrType)};
|
73
|
-
}
|
74
|
-
|
75
|
-
// HACK: somehow this is not set by Ext (while it should be)
|
76
|
-
// if (c.xtype == 'datecolumn') c.format = c.format || Ext.util.Format.dateFormat;
|
77
|
-
// setting dataIndex
|
78
|
-
// c.dataIndex = c.name;
|
79
|
-
|
80
|
-
}, this);
|
81
|
-
/* ... and done with the columns */
|
82
|
-
|
83
|
-
// Define the model
|
84
|
-
Ext.define(this.id, {
|
85
|
-
extend: 'Ext.data.Model',
|
86
|
-
idProperty: this.pri, // Primary key
|
87
|
-
fields: fields
|
88
|
-
});
|
89
|
-
|
90
|
-
// After we created the record (model), we can get rid of the meta column
|
91
|
-
Ext.Array.remove(this.columns, metaColumn);
|
92
|
-
|
93
|
-
// Prepare column model config with columns in the correct order; columns out of order go to the end.
|
94
|
-
var colModelConfig = [];
|
95
|
-
var columns = this.columns;
|
96
|
-
|
97
|
-
Ext.each(this.columns, function(c) {
|
98
|
-
var mainColConfig;
|
99
|
-
Ext.each(this.columns, function(oc) {
|
100
|
-
if (c.name === oc.name) {
|
101
|
-
mainColConfig = Ext.apply({}, oc);
|
102
|
-
return false;
|
103
|
-
}
|
104
|
-
});
|
105
|
-
|
106
|
-
colModelConfig.push(Ext.apply(mainColConfig, c));
|
107
|
-
}, this);
|
108
|
-
|
109
|
-
// We don't need original columns any longer
|
110
|
-
delete this.columns;
|
111
|
-
|
112
|
-
// ... instead, define own column model
|
113
|
-
this.columns = colModelConfig;
|
114
|
-
|
115
|
-
// DirectProxy that uses our Ext.direct provider
|
116
|
-
var proxy = Ext.create('Ext.data.proxy.Direct', {
|
117
|
-
|
118
|
-
directFn: Netzke.providers[this.id].getData,
|
119
|
-
// reader: Ext.create('Ext.data.reader.Array', {root: 'data', totalProperty: 'total'}),
|
120
|
-
reader: {
|
121
|
-
type: 'json',
|
122
|
-
root: 'data'
|
123
|
-
},
|
124
|
-
listeners: {
|
125
|
-
exception: {
|
126
|
-
fn: this.loadExceptionHandler,
|
127
|
-
scope: this
|
128
|
-
},
|
129
|
-
load: { // Netzke-introduced event; this will also be fired when an exception occurs.
|
130
|
-
fn: function(proxy, response, operation) {
|
131
|
-
// besides getting data into the store, we may also get commands to execute
|
132
|
-
response = response.result;
|
133
|
-
|
134
|
-
if (response) { // or did we have an exception?
|
135
|
-
Ext.each(['data', 'total', 'success'], function(property){delete response[property];});
|
136
|
-
this.netzkeBulkExecute(response);
|
137
|
-
}
|
138
|
-
},
|
139
|
-
scope: this
|
140
|
-
}
|
141
|
-
}
|
142
|
-
})
|
143
|
-
|
144
|
-
// Create the netzke PagingTreeStore
|
145
|
-
|
146
|
-
this.store = Ext.create('Ext.data.TreeStore', Ext.apply({
|
147
|
-
model: this.id,
|
148
|
-
proxy: proxy,
|
149
|
-
autoLoad: !this.loadInlineData,
|
150
|
-
// root: this.inlineData || {data: [{tree:'root', id:0}]}
|
151
|
-
}, this.dataStore));
|
152
|
-
delete this.dataStore;
|
153
|
-
|
154
|
-
this.store.load();
|
155
|
-
// HACK: we must let the store now totalCount
|
156
|
-
// this.store.setTotalCount(this.inlineData && this.inlineData[this.store.getProxy().getReader().totalProperty]);
|
157
|
-
|
158
|
-
// Drag'n'Drop
|
159
|
-
if (this.enableRowsReordering){
|
160
|
-
this.ddPlugin = new Ext.ux.dd.GridDragDropRowOrder({
|
161
|
-
scrollable: true // enable scrolling support (default is false)
|
162
|
-
});
|
163
|
-
this.plugins.push(this.ddPlugin);
|
164
|
-
}
|
165
|
-
|
166
|
-
// Cell editing
|
167
|
-
if (!this.prohibitUpdate) {
|
168
|
-
this.plugins.push(Ext.create('Ext.grid.plugin.CellEditing', {pluginId: 'celleditor'}));
|
169
|
-
}
|
170
|
-
|
171
|
-
// Toolbar
|
172
|
-
this.dockedItems = this.dockedItems || [];
|
173
|
-
if (this.enablePagination) {
|
174
|
-
this.dockedItems.push({
|
175
|
-
xtype: 'pagingtoolbar',
|
176
|
-
dock: 'bottom',
|
177
|
-
store: this.store,
|
178
|
-
// append the old bbar. TODO: get rid of it.
|
179
|
-
items: this.bbar && ["-"].concat(this.bbar)
|
180
|
-
});
|
181
|
-
} else if (this.bbar) {
|
182
|
-
this.dockedItems.push({
|
183
|
-
xtype: 'toolbar',
|
184
|
-
dock: 'bottom',
|
185
|
-
items: this.bbar
|
186
|
-
});
|
187
|
-
}
|
188
|
-
|
189
|
-
delete this.bbar;
|
190
|
-
|
191
|
-
// Now let Ext.grid.EditorGridPanel do the rest (original initComponent)
|
192
|
-
this.callParent();
|
193
|
-
|
194
|
-
// Context menu
|
195
|
-
if (this.contextMenu) {
|
196
|
-
this.on('itemcontextmenu', this.onItemContextMenu, this);
|
197
|
-
}
|
198
|
-
|
199
|
-
// Disabling/enabling editInForm button according to current selection
|
200
|
-
if (this.enableEditInForm && !this.prohibitUpdate) {
|
201
|
-
this.getSelectionModel().on('selectionchange', function(selModel, selected){
|
202
|
-
var disabled;
|
203
|
-
if (selected.length === 0) { // empty?
|
204
|
-
disabled = true;
|
205
|
-
} else {
|
206
|
-
// Disable "edit in form" button if new record is present in selection
|
207
|
-
Ext.each(selected, function(r){
|
208
|
-
if (r.isNew) { disabled = true; return false; }
|
209
|
-
});
|
210
|
-
};
|
211
|
-
this.actions.editInForm.setDisabled(disabled);
|
212
|
-
}, this);
|
213
|
-
}
|
214
|
-
|
215
|
-
|
216
|
-
// Drag n Drop event
|
217
|
-
if (this.enableRowsReordering){
|
218
|
-
this.ddPlugin.on('afterrowmove', this.onAfterRowMove, this);
|
219
|
-
}
|
220
|
-
|
221
|
-
// WIP: GridView
|
222
|
-
this.getView().getRowClass = this.defaultGetRowClass;
|
223
|
-
|
224
|
-
// When starting editing as assocition column, pre-load the combobox store from the meta column, so that we don't see the real value of this cell (the id of the associated record), but rather the associated record by the configured method.
|
225
|
-
this.on('beforeedit', function(e){
|
226
|
-
return false;
|
227
|
-
}, this);
|
228
|
-
|
229
|
-
this.on('afterrender', function() {
|
230
|
-
// Persistence-related events (afterrender to avoid blank event firing on render)
|
231
|
-
if (this.persistence) {
|
232
|
-
// Inform the server part about column operations
|
233
|
-
this.on('columnresize', this.onColumnResize, this);
|
234
|
-
this.on('columnmove', this.onColumnMove, this);
|
235
|
-
this.on('columnhide', this.onColumnHide, this);
|
236
|
-
this.on('columnshow', this.onColumnShow, this);
|
237
|
-
}
|
238
|
-
}, this);
|
239
|
-
},
|
240
|
-
|
241
|
-
fieldTypeForAttrType: function(attrType){
|
242
|
-
var map = {
|
243
|
-
integer : 'int',
|
244
|
-
decimal : 'float',
|
245
|
-
datetime : 'date',
|
246
|
-
date : 'date',
|
247
|
-
string : 'string',
|
248
|
-
text : 'string',
|
249
|
-
'boolean' : 'boolean'
|
250
|
-
};
|
251
|
-
return map[attrType] || 'string';
|
252
|
-
},
|
253
|
-
|
254
|
-
// Normalizes the renderer for a column.
|
255
|
-
// Renderer may be:
|
256
|
-
// 1) a string that contains the name of the function to be used as renderer.
|
257
|
-
// 2) an array, where the first element is the function name, and the rest - the arguments
|
258
|
-
// that will be passed to that function along with the value to be rendered.
|
259
|
-
// The function is searched in the following objects: 1) Ext.util.Format, 2) this.
|
260
|
-
// If not found, it is simply evaluated. Handy, when as renderer we receive an inline JS function,
|
261
|
-
// or reference to a function in some other scope.
|
262
|
-
// So, these will work:
|
263
|
-
// * "uppercase"
|
264
|
-
// * ["ellipsis", 10]
|
265
|
-
// * ["substr", 3, 5]
|
266
|
-
// * "myRenderer" (if this.myRenderer is a function)
|
267
|
-
// * ["Some.scope.Format.customRenderer", 10, 20, 30] (if Some.scope.Format.customRenderer is a function)
|
268
|
-
// * "function(v){ return 'Value: ' + v; }"
|
269
|
-
normalizeRenderer: function(c) {
|
270
|
-
if (!c.renderer) return;
|
271
|
-
|
272
|
-
var name, args = [];
|
273
|
-
|
274
|
-
if ('string' === typeof c.renderer) {
|
275
|
-
name = c.renderer.camelize(true);
|
276
|
-
} else {
|
277
|
-
name = c.renderer[0];
|
278
|
-
args = c.renderer.slice(1);
|
279
|
-
}
|
280
|
-
|
281
|
-
// First check whether Ext.util.Format has it
|
282
|
-
if (Ext.isFunction(Ext.util.Format[name])) {
|
283
|
-
c.renderer = Ext.Function.bind(Ext.util.Format[name], this, args, 1);
|
284
|
-
} else if (Ext.isFunction(this[name])) {
|
285
|
-
// ... then if our own class has it
|
286
|
-
c.renderer = Ext.Function.bind(this[name], this, args, 1);
|
287
|
-
} else {
|
288
|
-
// ... and, as last resort, evaluate it (allows passing inline javascript function as renderer)
|
289
|
-
eval("c.renderer = " + c.renderer + ";");
|
290
|
-
}
|
291
|
-
},
|
292
|
-
|
293
|
-
/*
|
294
|
-
Set a renderer that displayes association values instead of association record ID.
|
295
|
-
The association values are passed in the meta-column under associationValues hash.
|
296
|
-
*/
|
297
|
-
normalizeAssociationRenderer: function(c) {
|
298
|
-
c.scope = this;
|
299
|
-
var passedRenderer = c.renderer; // renderer we got from normalizeRenderer
|
300
|
-
c.renderer = function(value, a, r, ri, ci){
|
301
|
-
var column = this.headerCt.items.getAt(ci),
|
302
|
-
editor = column.getEditor && column.getEditor(),
|
303
|
-
recordFromStore = editor && editor.isXType('combobox') && editor.getStore().findRecord('value', value),
|
304
|
-
renderedValue;
|
305
|
-
|
306
|
-
if (recordFromStore) {
|
307
|
-
renderedValue = recordFromStore.get('text');
|
308
|
-
} else if (c.assoc && r.get('meta')) {
|
309
|
-
renderedValue = r.get('meta').associationValues[c.name] || c.emptyText;
|
310
|
-
} else {
|
311
|
-
renderedValue = value;
|
312
|
-
}
|
313
|
-
|
314
|
-
return passedRenderer ? passedRenderer.call(this, renderedValue) : renderedValue;
|
315
|
-
};
|
316
|
-
}
|
317
|
-
}
|