tramway 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +889 -15
  4. data/Rakefile +8 -8
  5. data/app/assets/config/tramway_core_manifest.js +2 -0
  6. data/app/assets/images/tramway/mona_lisa_from_prado.jpg +0 -0
  7. data/app/assets/images/tramway/mona_lisa_from_prado_square.jpg +0 -0
  8. data/app/assets/javascripts/bootstrap-datepicker-1.8.0.js +2035 -0
  9. data/app/assets/javascripts/bootstrap-datepicker-1.8.0.ru.min.js +64 -0
  10. data/app/assets/javascripts/ckeditor/config.js +30 -0
  11. data/app/assets/javascripts/ckeditor/plugins/image/dialogs/image.js +1259 -0
  12. data/app/assets/javascripts/ckeditor/plugins/image/icons/hidpi/image.png +0 -0
  13. data/app/assets/javascripts/ckeditor/plugins/image/icons/image.png +0 -0
  14. data/app/assets/javascripts/ckeditor/plugins/image/images/noimage.png +0 -0
  15. data/app/assets/javascripts/ckeditor/plugins/image/lang/en.js +25 -0
  16. data/app/assets/javascripts/ckeditor/plugins/image/lang/ru.js +25 -0
  17. data/app/assets/javascripts/ckeditor/plugins/image/plugin.js +184 -0
  18. data/app/assets/javascripts/ckeditor/plugins/youtube/images/icon-hdpi.png +0 -0
  19. data/app/assets/javascripts/ckeditor/plugins/youtube/images/icon.png +0 -0
  20. data/app/assets/javascripts/ckeditor/plugins/youtube/lang/en.js +25 -0
  21. data/app/assets/javascripts/ckeditor/plugins/youtube/lang/ru.js +25 -0
  22. data/app/assets/javascripts/ckeditor/plugins/youtube/plugin.js +449 -0
  23. data/app/assets/javascripts/tramway/application.js +60 -0
  24. data/app/assets/stylesheets/tramway/application.sass +60 -0
  25. data/app/assets/stylesheets/tramway/bootstrap-datepicker-1.8.0.css +477 -0
  26. data/app/controllers/concerns/auth_management.rb +26 -0
  27. data/app/controllers/concerns/filtering.rb +43 -0
  28. data/app/controllers/tramway/application_controller.rb +142 -0
  29. data/app/controllers/tramway/export/application_controller.rb +5 -0
  30. data/app/controllers/tramway/has_and_belongs_to_many_records_controller.rb +26 -0
  31. data/app/controllers/tramway/records_controller.rb +86 -0
  32. data/app/controllers/tramway/sessions_controller.rb +49 -0
  33. data/app/controllers/tramway/singletons_controller.rb +48 -0
  34. data/app/controllers/tramway/welcome_controller.rb +17 -0
  35. data/app/decorators/tramway/application_decorated_collection.rb +15 -0
  36. data/app/decorators/tramway/application_decorator.rb +124 -0
  37. data/app/decorators/tramway/associations/class_helper.rb +45 -0
  38. data/app/decorators/tramway/associations/object_helper.rb +58 -0
  39. data/app/decorators/tramway/attributes/view_helper.rb +30 -0
  40. data/app/decorators/tramway/concerns/attributes_decorator_helper.rb +97 -0
  41. data/app/decorators/tramway/concerns/table_builder.rb +33 -0
  42. data/app/decorators/tramway/default/values_helper.rb +23 -0
  43. data/app/decorators/tramway/delegating/class_helper.rb +9 -0
  44. data/app/decorators/tramway/user_decorator.rb +49 -0
  45. data/app/forms/admin/tramway/user_form.rb +24 -0
  46. data/app/forms/tramway/application_form.rb +124 -0
  47. data/app/forms/tramway/application_forms/association_class_helpers.rb +7 -0
  48. data/app/forms/tramway/application_forms/association_object_helpers.rb +36 -0
  49. data/app/forms/tramway/application_forms/constant_class_actions.rb +7 -0
  50. data/app/forms/tramway/application_forms/constant_object_actions.rb +20 -0
  51. data/app/forms/tramway/application_forms/frontend.rb +12 -0
  52. data/app/forms/tramway/application_forms/object_helpers.rb +15 -0
  53. data/app/forms/tramway/application_forms/properties_object_helper.rb +16 -0
  54. data/app/forms/tramway/application_forms/submit_helper.rb +26 -0
  55. data/app/forms/tramway/extendable_form.rb +15 -0
  56. data/app/forms/tramway/extendable_forms_helpers/class_builder.rb +34 -0
  57. data/app/forms/tramway/extendable_forms_helpers/ignored_properties_helper.rb +11 -0
  58. data/app/forms/tramway/extendable_forms_helpers/more_properties_helper.rb +31 -0
  59. data/app/forms/tramway/extendable_forms_helpers/properties_helper.rb +16 -0
  60. data/app/forms/tramway/extendable_forms_helpers/submit/class_helpers.rb +18 -0
  61. data/app/forms/tramway/extendable_forms_helpers/submit/object_helpers.rb +21 -0
  62. data/app/forms/tramway/extendable_forms_helpers/validators.rb +40 -0
  63. data/app/forms/tramway/extended_application_form.rb +23 -0
  64. data/app/forms/tramway/form_creator.rb +7 -0
  65. data/app/forms/tramway/session_form.rb +26 -0
  66. data/app/helpers/tramway/actions_helper.rb +45 -0
  67. data/app/helpers/tramway/additional_buttons_builder.rb +12 -0
  68. data/app/helpers/tramway/application_helper.rb +27 -0
  69. data/app/helpers/tramway/cases_helper.rb +13 -0
  70. data/app/helpers/tramway/copy_to_clipboard_helper.rb +11 -0
  71. data/app/helpers/tramway/focus_generator_helper.rb +10 -0
  72. data/app/helpers/tramway/frontend_helper.rb +26 -0
  73. data/app/helpers/tramway/inputs/associations_helper.rb +30 -0
  74. data/app/helpers/tramway/inputs/polymorphic_associations_helper.rb +24 -0
  75. data/app/helpers/tramway/inputs_helper.rb +96 -0
  76. data/app/helpers/tramway/model_helper.rb +7 -0
  77. data/app/helpers/tramway/navbar_helper.rb +11 -0
  78. data/app/helpers/tramway/records_helper.rb +120 -0
  79. data/app/helpers/tramway/russian_cases_helper.rb +26 -0
  80. data/app/helpers/tramway/singleton_helper.rb +12 -0
  81. data/app/helpers/tramway/state_machine_buttons_helper.rb +61 -0
  82. data/app/helpers/tramway/title_helper.rb +25 -0
  83. data/app/inputs/date_picker_input.rb +4 -0
  84. data/app/inputs/multiple_file_input.rb +7 -0
  85. data/app/models/tramway/application_record.rb +60 -0
  86. data/app/models/tramway/user.rb +23 -0
  87. data/app/uploaders/application_uploader.rb +22 -0
  88. data/app/uploaders/file_uploader.rb +4 -0
  89. data/app/uploaders/ico_uploader.rb +7 -0
  90. data/app/uploaders/image_defaults.rb +14 -0
  91. data/app/uploaders/photo_uploader.rb +54 -0
  92. data/app/views/layouts/tramway/application.html.haml +32 -0
  93. data/app/views/layouts/tramway/shared/_navbar.html.haml +46 -0
  94. data/app/views/tramway/404.haml +1 -0
  95. data/app/views/tramway/records/_form.html.haml +22 -0
  96. data/app/views/tramway/records/_list.html.haml +38 -0
  97. data/app/views/tramway/records/_search.html.haml +34 -0
  98. data/app/views/tramway/records/edit.html.haml +1 -0
  99. data/app/views/tramway/records/index.html.haml +31 -0
  100. data/app/views/tramway/records/new.html.haml +1 -0
  101. data/app/views/tramway/records/show.html.haml +1 -0
  102. data/app/views/tramway/sessions/new.html.haml +9 -0
  103. data/app/views/tramway/shared/_input.html.haml +34 -0
  104. data/app/views/tramway/shared/_input_extended.html.haml +14 -0
  105. data/app/views/tramway/shared/_messages.html.haml +10 -0
  106. data/app/views/tramway/shared/_show.html.haml +35 -0
  107. data/app/views/tramway/shared/errors/server_error.html.haml +12 -0
  108. data/app/views/tramway/shared/input_extended_types/_checkbox.html.haml +1 -0
  109. data/app/views/tramway/shared/input_extended_types/_select.html.haml +16 -0
  110. data/app/views/tramway/shared/input_extended_types/_simple.html.haml +4 -0
  111. data/app/views/tramway/shared/input_extended_types/_yes_no.html.haml +4 -0
  112. data/app/views/tramway/shared/show/_attribute_tr.html.haml +9 -0
  113. data/app/views/tramway/shared/show/associations/_habtm_row.html.haml +14 -0
  114. data/app/views/tramway/shared/show/associations/_list.html.haml +21 -0
  115. data/app/views/tramway/shared/show/associations/_row.html.haml +19 -0
  116. data/app/views/tramway/shared/show/associations/_table_row.html.haml +21 -0
  117. data/app/views/tramway/singletons/_form.html.haml +15 -0
  118. data/app/views/tramway/singletons/edit.html.haml +1 -0
  119. data/app/views/tramway/singletons/new.html.haml +1 -0
  120. data/app/views/tramway/singletons/show.html.haml +1 -0
  121. data/app/views/tramway/welcome/index.html.haml +4 -0
  122. data/config/initializers/assets.rb +7 -0
  123. data/config/initializers/carrierwave.rb +5 -0
  124. data/config/initializers/ckeditor.rb +9 -0
  125. data/config/initializers/plurals.rb +25 -0
  126. data/config/locales/en/collections.yml +4 -0
  127. data/config/locales/en/date.yml +16 -0
  128. data/config/locales/en/dates.yml +10 -0
  129. data/config/locales/en/helpers.yml +26 -0
  130. data/config/locales/en/locale.yml +11 -0
  131. data/config/locales/en/messages.yml +7 -0
  132. data/config/locales/en/models.yml +9 -0
  133. data/config/locales/en/simple_form_extension.yml +8 -0
  134. data/config/locales/en/state_machines.yml +8 -0
  135. data/config/locales/ru/collections.yml +4 -0
  136. data/config/locales/ru/date.yml +16 -0
  137. data/config/locales/ru/dates.yml +10 -0
  138. data/config/locales/ru/helpers.yml +30 -0
  139. data/config/locales/ru/locale.yml +6 -0
  140. data/config/locales/ru/messages.yml +7 -0
  141. data/config/locales/ru/models.yml +21 -0
  142. data/config/locales/ru/simple_form_extension.yml +8 -0
  143. data/config/locales/ru/state_machines.yml +8 -0
  144. data/config/routes.rb +13 -0
  145. data/lib/string.rb +18 -0
  146. data/lib/tramway/application.rb +10 -0
  147. data/lib/tramway/class_name_helpers.rb +15 -0
  148. data/lib/tramway/collection.rb +9 -0
  149. data/lib/tramway/collections/helper.rb +21 -0
  150. data/lib/tramway/collections.rb +4 -0
  151. data/lib/tramway/engine.rb +14 -0
  152. data/lib/tramway/error.rb +32 -0
  153. data/lib/tramway/forms.rb +5 -0
  154. data/lib/tramway/generators/install_generator.rb +49 -0
  155. data/lib/tramway/generators/model_generator.rb +105 -0
  156. data/lib/tramway/generators/templates/create_tramway_users.rb +18 -0
  157. data/lib/tramway/generators/templates/decorator.rb.erb +56 -0
  158. data/lib/tramway/generators/templates/form.rb.erb +22 -0
  159. data/lib/tramway/generators/templates/initializers/simple_form.rb +23 -0
  160. data/lib/tramway/generators/templates/initializers/simple_form_bootstrap.rb +133 -0
  161. data/lib/tramway/generators.rb +4 -0
  162. data/lib/tramway/navbar.rb +44 -0
  163. data/lib/tramway/notifications.rb +12 -0
  164. data/lib/tramway/record_routes_helper.rb +23 -0
  165. data/lib/tramway/records_models.rb +52 -0
  166. data/lib/tramway/singleton_models.rb +32 -0
  167. data/lib/tramway/spec/helpers/navbar_helper.rb +7 -0
  168. data/lib/tramway/spec/helpers/tramway_helpers.rb +47 -0
  169. data/lib/tramway/version.rb +3 -1
  170. data/lib/tramway/welcome_page_actions.rb +5 -0
  171. data/lib/tramway/yaml/errors.yml +49 -0
  172. data/lib/tramway.rb +143 -2
  173. data/lib/validators/presence_validator.rb +9 -0
  174. metadata +582 -25
  175. data/.gitignore +0 -9
  176. data/.travis.yml +0 -5
  177. data/Gemfile +0 -6
  178. data/bin/console +0 -14
  179. data/bin/setup +0 -8
  180. data/tramway.gemspec +0 -26
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PhotoUploader < ApplicationUploader
4
+ include ImageDefaults
5
+
6
+ def default_url
7
+ ActionController::Base.helpers.asset_path('mona_lisa_from_prado_square.png')
8
+ end
9
+
10
+ def url
11
+ if file.present? && File.exist?(file.file)
12
+ file.file.match(%r{/system/uploads/.*}).to_s
13
+ else
14
+ default_url = '/assets/tramway/mona_lisa_from_prado_square.jpg'
15
+ File.exist?(default_url) ? default_url : ''
16
+ end
17
+ end
18
+
19
+ version :medium, if: :medium_version_is_needed? do
20
+ process resize_to_fill: [400, 400]
21
+ end
22
+
23
+ version :small, if: :small_version_is_needed? do
24
+ process resize_to_fill: [100, 100]
25
+ end
26
+
27
+ attr_reader :width, :height
28
+
29
+ before :cache, :capture_size
30
+
31
+ def capture_size(file)
32
+ return unless version_name.blank?
33
+
34
+ if file.path.nil?
35
+ img = ::MiniMagick::Image.read(file.file)
36
+ @width = img[:width]
37
+ @height = img[:height]
38
+ else
39
+ @width, @height = `identify -format "%wx %h" #{file.path}`.split(/x/).map(&:to_i)
40
+ end
41
+ end
42
+
43
+ def medium_version_is_needed?(_new_file)
44
+ version_is_needed? :medium
45
+ end
46
+
47
+ def small_version_is_needed?(_new_file)
48
+ version_is_needed? :small
49
+ end
50
+
51
+ def version_is_needed?(version)
52
+ model.class.photo_versions&.include? version
53
+ end
54
+ end
@@ -0,0 +1,32 @@
1
+ %html
2
+ %head
3
+ %meta{ content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type" }
4
+ %meta{ content: "width=device-width, initial-scale=1, maximum-scale=0.8", name: "viewport" }
5
+ %title
6
+ = yield :title
7
+ = stylesheet_link_tag 'tramway/application', media: :all
8
+ = javascript_include_tag 'tramway/application'
9
+ - if File.exists?("#{Rails.root}/app/assets/javascripts/application.js") || File.exists?("#{Rails.root}/app/assets/javascripts/application.js.coffee")
10
+ = javascript_include_tag 'application'
11
+ - if File.exists?("#{Rails.root}/app/assets/stylesheets/application.css") || File.exists?("#{Rails.root}/app/assets/stylesheets/application.scss")
12
+ = stylesheet_link_tag 'application'
13
+ - if File.exists?("#{Rails.root}/app/javascript/packs/application.js")
14
+ = javascript_pack_tag 'application'
15
+ = csrf_meta_tags
16
+ - if @application.favicon.present?
17
+ = favicon_link_tag @application.favicon
18
+ %body
19
+ = render 'layouts/tramway/shared/navbar'
20
+ %main.container{ role: :main }
21
+ .row
22
+ - if content_for?(:sidebar)
23
+ .col-lg-9
24
+ = yield
25
+ .col-lg-3.sidebar-canvas
26
+ = yield :sidebar
27
+ - else
28
+ .col-lg-12
29
+ = yield
30
+ %footer
31
+ .container
32
+ = copyright '2017', 'Tramway'
@@ -0,0 +1,46 @@
1
+ %nav.navbar.navbar-expand-md.navbar-dark.bg-dark
2
+ - if Tramway.customized_admin_navbar.present?
3
+ = Tramway.customized_admin_navbar
4
+ - else
5
+ .container-fluid
6
+ = link_to @application&.try(:title) || @application&.public_name || t('aplication.title'), ::Tramway::Engine.routes.url_helpers.root_path, class: 'navbar-brand'
7
+ %button.navbar-toggler.collapsed{ aria: { controls: :navbar, expanded: "false", label: 'Toggle Navigation' }, data: { bs: { target: "#navbar" , toggle: :collapse } }, type: :button }
8
+ %span.navbar-toggler-icon
9
+ .navbar-collapse.collapse#navbar
10
+ - if current_user
11
+ %ul.navbar-nav
12
+ - ::Tramway.navbar_items_for(@application_engine || @application.name, role: current_user.role)&.each do |item|
13
+ - case item.keys.first
14
+ - when Class, String
15
+ - model = item.keys.first.is_a?(String) ? item.keys.first.constantize : item.keys.first
16
+ - case item.values.first
17
+ - when :singleton
18
+ = model_menu_item model: model, route: ::Tramway::Engine.routes.url_helpers.singleton_path(model: model)
19
+ - when :record
20
+ = model_menu_item model: model, route: ::Tramway::Engine.routes.url_helpers.records_path(model: model, scope: decorator_class(model).collections.first), pluralize: plural(model.model_name).capitalize
21
+ - when Symbol, String
22
+ = dropdown t("admin.navbar.links.#{item.keys.first}") do
23
+ - item.values.first.each do |sub_item|
24
+ - if sub_item == :divider
25
+ = dropdown_divider
26
+ - else
27
+ - model = sub_item.keys.first
28
+ - if sub_item.values.first == :singleton
29
+ = dropdown_model_item model: model, route: ::Tramway::Engine.routes.url_helpers.singleton_path(model: model)
30
+ - if sub_item.values.first == :record
31
+ = dropdown_model_item model: model, route: ::Tramway::Engine.routes.url_helpers.records_path(model: model, scope: decorator_class(model).collections.first), pluralize: plural(model.constantize.model_name).capitalize
32
+
33
+ %ul.nav.navbar-nav.ml-auto.justify-content-end.navbar-collapse.collapse
34
+ - if current_user
35
+ %li.nav-item
36
+ %span.nav-link
37
+ = "#{current_user.first_name} #{current_user.last_name}"
38
+ %li.nav-item
39
+ = link_to '/admin/sign_out', class: 'nav-link' do
40
+ = fa_icon 'sign-out-alt'
41
+ = t('helpers.links.sign_out')
42
+ - else
43
+ %li.nav-item
44
+ = link_to new_session_path, class: 'nav-link' do
45
+ = fa_icon 'sign-in-alt'
46
+ = t('helpers.links.enter')
@@ -0,0 +1 @@
1
+ != @message
@@ -0,0 +1,22 @@
1
+ - current_title = page_title(action, model_class)
2
+ - title current_title
3
+ .page-header
4
+ %h1= current_title
5
+ %hr
6
+ .row
7
+ .col-lg-12
8
+ = render 'tramway/shared/messages', object: @record_form
9
+ .row
10
+ .col-lg-12
11
+ - if @record_form.class.react_component?
12
+ = react_component "#{@record_form.class.name.gsub('::', '/')}", react_params(@record_form, action, method)
13
+ - else
14
+ = simple_form_for @record_form, url: { controller: :records, action: action, model: @record_form.model.class }, method: method, input_html: { class: 'form-horizontal' } do |f|
15
+ - @record_form.properties.each do |property, type|
16
+ = render 'tramway/shared/input', property: property, object: :record, type: type, form: f, destination: :admin, value: value_from_params(model_class: model_class, property: property, type: type)
17
+ = hidden_field_tag :redirect, params[:redirect]
18
+ = f.button :submit, t('helpers.links.save'), class: 'btn btn-success'
19
+ = link_to t('helpers.links.back'), current_model_records_path, class: 'btn btn-secondary'
20
+
21
+ -# NOTES
22
+ -# * value_from_params helper is in tramway gem app/helpers/inputs_helpers.rb
@@ -0,0 +1,38 @@
1
+ = paginate @records, theme: 'twitter-bootstrap-4'
2
+ %table.table.table-striped.table-hover
3
+ %thead
4
+ %tr
5
+ %th{ scope: :col }
6
+ = model_class.human_attribute_name(:id)
7
+ %th{ scope: :col }
8
+ = model_class.human_attribute_name(:name)
9
+ - decorator_class.list_attributes.each do |attribute|
10
+ %th{ scope: :col }
11
+ = model_class.human_attribute_name attribute
12
+ %th{ scope: :col }
13
+ = t 'helpers.links.actions'
14
+ %tbody
15
+ - @records.each_with_index do |record, index|
16
+ - model_name = record.class.model_name.name
17
+ %tr
18
+ %th{ scope: :row }
19
+ = link_to record.id, current_model_record_path(record.id)
20
+ %td.link{ data: { href: current_model_record_path(record.id) } }
21
+ = link_to record.name, current_model_record_path(record.id)
22
+ - decorator_class.list_attributes.each do |attribute|
23
+ %td
24
+ = record.send attribute
25
+ %td.actions
26
+ - if update_is_available? record
27
+ = link_to fa_icon('pencil-alt'), edit_current_model_record_path(record.id, redirect: current_model_records_path(record.id)), class: 'btn btn-warning btn-xs'
28
+ - if destroy_is_available?(record)
29
+ = delete_button url: current_model_record_path(record.id), form_options: { class: :smart_button }, button_options: { class: 'btn btn-xs btn-danger' } do
30
+ = fa_icon 'trash-alt'
31
+ - if tramway_model?(model_class)
32
+ %br
33
+ %br
34
+ .btn-group{ data: { toggle: :buttons } }
35
+ - state_machine_names = record.listed_state_machines || record.model.class.state_machines_names
36
+ - state_machine_names.each do |state_machine_name|
37
+ = state_events_buttons record, state_method: state_machine_name, model_param_name: :record, parameters: { redirect: current_model_records_path(page: params[:page], scope: params[:scope], filter: params[:filter], focus: focus_selector(index)), model: model_name }, button_options: { class: :smart_button }
38
+ = paginate @records, theme: 'twitter-bootstrap-4'
@@ -0,0 +1,34 @@
1
+ - if searchable_model?(model_class) || there_any_filters?(model_class)
2
+ .search
3
+ .d-flex.flex-row-reverse.filters
4
+ = form_tag records_path, class: 'form-inline', method: :get do |f|
5
+ - if searchable_model?(model_class)
6
+ .input-group
7
+ = text_field_tag :search, params[:search], class: 'text form-control'
8
+ = submit_tag t('helpers.actions.search'), class: 'btn btn-primary'
9
+ = hidden_field_tag :model, params[:model]
10
+ = hidden_field_tag :scope, params[:scope]
11
+ = hidden_field_tag :filter, (params[:filter].is_a?(ActionController::Parameters) ? params[:filter].permit!.to_h.to_json : params[:filter])
12
+ - decorator_class(model_class).list_filters&.each_slice(3) do |slice|
13
+ .row-fluid.filters
14
+ - slice.each do |filter|
15
+ - case filter[1][:type]
16
+ - when :select
17
+ .col-md-4
18
+ = label_tag t("filters.#{model_class.to_s.underscore}.#{filter[0]}")
19
+ = select_tag "list_filters[#{filter[0]}]", build_options_for_select(filter[0], filter[1][:select_collection]), include_blank: true, class: 'form-control'
20
+ - when :dates
21
+ .col-md-8.dates_filter
22
+ .begin_date
23
+ = label_tag t("filters.#{model_class.to_s.underscore}.#{filter[0]}.begin_date")
24
+ = text_field_tag "list_filters[#{filter[0]}][begin_date]", '', class: 'form-control', id: 'filter_datepicker_begin_date', value: params.dig(:list_filters, filter[0], :begin_date)
25
+ %span
26
+ \ -
27
+ .end_date
28
+ = label_tag t("filters.#{model_class.to_s.underscore}.#{filter[0]}.end_date")
29
+ = text_field_tag "list_filters[#{filter[0]}][end_date]", '', class: 'form-control', id: 'filter_datepicker_end_date', value: params.dig(:list_filters, filter[0], :end_date)
30
+ :javascript
31
+ $(function () {
32
+ $('#filter_datepicker_begin_date').datepicker();
33
+ $('#filter_datepicker_end_date').datepicker();
34
+ });
@@ -0,0 +1 @@
1
+ = render partial: 'form', locals: { action: :update, method: :patch }
@@ -0,0 +1,31 @@
1
+ - default_page_title ||= nil; on_site_link ||= nil
2
+ - current_title = default_page_title || plural(model_class).capitalize
3
+ - title current_title
4
+ - state_method ||= :state
5
+ - tabs = decorator_class.collections
6
+ .page-header
7
+ .row
8
+ - search_render_show = searchable_model?(model_class) || there_any_filters?(model_class)
9
+ %div{ class: "col-md-#{search_render_show ? 4 : 12}" }
10
+ %h1
11
+ = current_title
12
+ - if create_is_available?(model_class.name)
13
+ = link_to fa_icon(:plus), new_current_model_record_path, class: 'btn btn-primary'
14
+ - if defined? Tramway::Export::Engine
15
+ = render 'tramway/export/button'
16
+ .col
17
+ = render 'search', model_class: model_class
18
+ %hr
19
+ %ul.nav.nav-tabs.mb-3
20
+ - if params[:search].present?
21
+ %li.nav-item
22
+ = link_to search_tab_title(@records.total_count), '#', class: 'nav-link active'
23
+ %li.nav-item
24
+ = link_to t('helpers.actions.reset'), records_path(model: params[:model], filter: params[:filter]), class: 'nav-link'
25
+ - else
26
+ - tabs.each_with_index do |tab, index|
27
+ %li.nav-item
28
+ = link_to index_path_of_model(model_class, tab, (params[:filter].present? ? params[:filter] : nil)&.permit!), class: "#{active_tab(tab, index)} nav-link" do
29
+ != tab_title(model_class, tab, @counts[tab], state_method)
30
+ %div{ id: (params[:search] ? :search : params[:scope]) }
31
+ = render 'list'
@@ -0,0 +1 @@
1
+ = render partial: 'form', locals: { action: :create, method: :post }
@@ -0,0 +1 @@
1
+ = render 'tramway/shared/show', object: @record
@@ -0,0 +1,9 @@
1
+ - title
2
+ .row
3
+ .col-md-6
4
+ = simple_form_for @session_form.model, url: Tramway::Engine.routes.url_helpers.session_path, method: :post, html: { class: 'form-horizontal' } do |f|
5
+ = f.input :email, as: :string
6
+ = f.input :password
7
+ = hidden_field_tag :model, @session_form.model.class.to_s
8
+ = hidden_field_tag :redirect, Tramway::Engine.routes.url_helpers.root_path
9
+ = f.button :submit, t('helpers.links.enter'), class: 'btn btn-success'
@@ -0,0 +1,34 @@
1
+ - model_class = defined?(record) ? record.model : model_class
2
+ - form_object = defined?(record) ? record : instance_variable_get("@#{object}_form")
3
+ - input_params = { property: property, object: object, form_object: form_object, value: value }
4
+ - if !type.class.in?([ Symbol, String ]) && type[:input_options]
5
+ - input_params.merge!(options: type[:input_options])
6
+ - type = type[:type]
7
+ - if type.class.in?([ Symbol, String ]) || type&.dig(:input_options)
8
+ - type = type.to_sym
9
+ - if !type.in?([ :hidden ]) && input_params.dig(:options, :label) != false
10
+ = form.label form_object.model.class.human_attribute_name property
11
+ - case type
12
+ - when :default
13
+ = form.input property, **default_params(**input_params)
14
+ - when :association
15
+ = form.association property, **association_params(**input_params)
16
+ - when :hidden_association
17
+ - if form_object.public_send(property)&.id
18
+ = form.association property, **association_params(**input_params).merge(as: :hidden, input_html: { value: form_object.public_send(property)&.id })
19
+ - else
20
+ = form.association property, **association_params(**input_params).merge(as: :hidden)
21
+ - when :polymorphic_association
22
+ = form.input property, **polymorphic_association_params(**input_params.merge(value: value))
23
+ - when :react_component
24
+ = react_component "#{property.camelize}Input", value: value
25
+ - else
26
+ - options = input_params[:options] || {}
27
+ = form.input property, **simple_params(**input_params.merge(type: type)).merge(options)
28
+ - else
29
+ - property_value = form_object.model.values.present? && form_object.model.values[property.to_s]
30
+ = render 'tramway/shared/input_extended', field: type[:extended_form_property], class_name: :record, value: property_value, f: form
31
+
32
+ - if params[:errors].present? && params[:errors][property]&.first
33
+ .alert.alert-danger
34
+ = params[:errors][property]&.first
@@ -0,0 +1,14 @@
1
+ - value = defined?(value).present? ? value : ''
2
+ - case field.field_type
3
+ - when 'text', 'string', 'numeric', 'date_picker', 'file'
4
+ = render 'tramway/shared/input_extended_types/simple', value: value, field: field, class_name: class_name, f: f
5
+ - when 'select'
6
+ = render 'tramway/shared/input_extended_types/select', value: value, field: field, class_name: class_name, f: f
7
+ - when 'yes_no'
8
+ = render 'tramway/shared/input_extended_types/yes_no', value: value, field: field, class_name: class_name, f: f
9
+ - when 'checkbox'
10
+ = render 'tramway/shared/input_extended_types/checkbox', value: value, field: field, class_name: class_name, f: f
11
+
12
+ - if params[:errors].present? && params[:errors][field.title]&.first
13
+ .alert.alert-danger
14
+ = params[:errors][field.title]&.first
@@ -0,0 +1,10 @@
1
+ - if object.model.errors.any?
2
+ - messages = (object.errors.full_messages + object.model.errors.full_messages).uniq
3
+ .alert.alert-dismissible.alert-danger
4
+ %h4= t('.some_errors_was_found')
5
+ %ul
6
+ - messages.each do |message|
7
+ %li= message
8
+ - if params[:message]
9
+ .alert.alert-dismissible.alert-info
10
+ %h4= t("messages.#{params[:message]}")
@@ -0,0 +1,35 @@
1
+ - default_page_title ||= nil; on_site_link ||= nil
2
+ - current_title = default_page_title || "#{object.name} | #{model_class.model_name.human.pluralize(I18n.locale)}"
3
+ - title current_title
4
+ .page-header
5
+ .row
6
+ .col-md-12
7
+ %h2
8
+ = current_title
9
+ - edit_path = object_type(object) == :singleton ? edit_current_model_singleton_path : edit_current_model_record_path(object.id)
10
+ = link_to fa_icon('pencil-alt'), edit_path, class: 'btn btn-warning btn-xs'
11
+ - if public_path(object)
12
+ = link_to fa_icon(:share), public_path(object), class: 'btn btn-primary btn-xs'
13
+ - buttons = object.additional_buttons&.dig :show
14
+ - buttons&.each do |button|
15
+ = link_to button[:url], method: button[:method], class: "btn btn-#{button[:color]}" do
16
+ - if button[:text].present?
17
+ = button[:text]
18
+ - if button[:inner].present?
19
+ = button[:inner].call
20
+ %hr
21
+ .row
22
+ %table.table.table-striped.table-bordered
23
+ - if object.class.show_attributes.any?
24
+ - object.class.show_attributes.each do |attribute_name|
25
+ - value = object.send attribute_name
26
+ = render 'tramway/shared/show/attribute_tr', attribute_name: attribute_name, value: value, object: object
27
+ - else
28
+ - object.attributes.each do |attribute_name, value|
29
+ = render 'tramway/shared/show/attribute_tr', attribute_name: attribute_name, value: value, object: object
30
+ - object.associations(:has_one).each do |association|
31
+ = render 'tramway/shared/show/associations/row', object: object, association: association
32
+ - object.associations(:has_many).each do |association|
33
+ = render 'tramway/shared/show/associations/row', object: object, association: association
34
+ - object.associations(:has_and_belongs_to_many).each do |association|
35
+ = render 'tramway/shared/show/associations/habtm_row', object: object, association: association
@@ -0,0 +1,12 @@
1
+ %h2
2
+ = @exception.message
3
+ - if @exception.try :source_extract
4
+ %ul
5
+ - @exception.source_extract.each do |line|
6
+ %li
7
+ = line
8
+ %ul
9
+ - @exception.backtrace.each do |line|
10
+ %li
11
+ = line
12
+
@@ -0,0 +1 @@
1
+ = f.input field.title.to_sym, as: :boolean, input_html: { class: class_name, id: "#{class_name}_#{field.title.to_sym}", name: "#{class_name}[#{field.title}]" }, checked_value: :true, unchecked_value: :false, required: field.required
@@ -0,0 +1,16 @@
1
+ - parsed_json = field.options&.is_a?(Hash) ? field.options : (JSON.parse(field.options) if field.options.present?)
2
+ - if parsed_json&.dig('collection', 'name')
3
+ - if value.present?
4
+ = f.input field.title.to_sym, as: :select, collection: collection_list_by(name: parsed_json['collection']['name']), input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, selected: value, required: field.required
5
+ - else
6
+ = f.input field.title.to_sym, as: :select, collection: collection_list_by(name: parsed_json['collection']['name']), input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, required: field.required
7
+ - elsif parsed_json&.dig('collection', 'array')
8
+ - if value.present?
9
+ = f.input field.title.to_sym, as: :select, collection: parsed_json.dig('collection', 'array'), input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, selected: value, required: field.required
10
+ - else
11
+ = f.input field.title.to_sym, as: :select, collection: parsed_json.dig('collection', 'array'), input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, required: field.required
12
+ - else
13
+ - if value.present?
14
+ = f.input field.title.to_sym, as: :select, input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, selected: value, required: field.required
15
+ - else
16
+ = f.input field.title.to_sym, as: :select, input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, required: field.required
@@ -0,0 +1,4 @@
1
+ - if value.present?
2
+ = f.input field.title.to_sym, as: field.field_type, input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]", value: value }, required: field.required
3
+ - else
4
+ = f.input field.title.to_sym, as: field.field_type, input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, required: field.required
@@ -0,0 +1,4 @@
1
+ - if value.present?
2
+ = f.input field.title.to_sym, as: :select, input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }, selected: value
3
+ - else
4
+ = f.input field.title.to_sym, as: :select, input_html: { class: class_name, id: "#{class_name}_#{field.title}", name: "#{class_name}[#{field.title}]" }
@@ -0,0 +1,9 @@
1
+ %tr
2
+ %td
3
+ = model_class.human_attribute_name attribute_name
4
+ %td
5
+ = value
6
+ %td
7
+ - if tramway_model?(model_class)
8
+ - if attribute_name.to_s != 'state' && object.model.class.aasm.states.map(&:name).include?(attribute_name.to_sym)
9
+ = state_events_buttons object, state_method: attribute_name, model_param_name: :record, controller: 'tramway/records', action: :update, parameters: { model: object.class.model_name }, button_options: { class: :smart_button }
@@ -0,0 +1,14 @@
1
+ - if object.class.show_associations.map(&:to_s).include? association.name.to_s
2
+ %tr
3
+ %td
4
+ = model_class.human_attribute_name association.name
5
+ %hr
6
+ - association_form = object.send("add_#{association.name}_form")
7
+ = simple_form_for association_form, url: { controller: :has_and_belongs_to_many_records, action: :create, form: association_form.class, model_class: model_class, object_id: object.id }, method: :post do |f|
8
+ - association_form.associations.each do |association_name|
9
+ - associations = association_form.model.class.reflect_on_all_associations.map(&:name)
10
+ - if associations.include? association_name
11
+ = f.association association_name, label: false
12
+ = f.button :submit, "#{I18n.t('helpers.actions.add')} #{model_class.human_attribute_name(association.name).singularize.downcase}", class: 'btn-success'
13
+ %td{ colspan: 2 }
14
+ = render 'tramway/shared/show/associations/list', object: object, association: association
@@ -0,0 +1,21 @@
1
+ - association_state_machines = object.send("#{association.name}_state_machines")
2
+ %table.table.table-striped.table-bordered
3
+ - object.send(association.name)&.each do |association_object|
4
+ %tr{ id: "#{association.name}_#{association_object.id}" }
5
+ %td
6
+ = association_object.id
7
+ %td
8
+ = link_to association_object.name, record_path(association_object.id, model: association.options[:class_name])
9
+ %td
10
+ - association_state_machines.each do |state_method|
11
+ = state_events_buttons association_object, state_method: state_method, model_param_name: :record, controller: 'tramway/records', action: :update, parameters: { redirect: current_model_record_path(object.id), model: association_object.class.model_name }, button_options: { class: :smart_button }
12
+ %td
13
+ - if update_is_available? association_object, object
14
+ = edit_button url: edit_record_path(association_object.id, model: association.options[:class_name], redirect: current_model_record_path(object.id)), button_options: { class: 'btn btn-xs btn-warning edit' } do
15
+ = fa_icon 'pencil-alt'
16
+ - if destroy_is_available? association_object, object
17
+ = delete_button url: record_path(association_object.id, model: association.options[:class_name], redirect: current_model_record_path(object.id)), button_options: { class: 'btn btn-xs btn-danger delete' } do
18
+ = fa_icon 'trash-alt'
19
+ - if habtm_destroy_is_available? association_object, object
20
+ = delete_button url: has_and_belongs_to_many_record_path(association_object.id, model_class: object.model.class, object_id: object.id, form: "Admin::#{object.model.class.to_s.pluralize}::Remove#{association_object.model.class.to_s}Form", redirect: current_model_record_path(object.id)), button_options: { class: 'btn btn-xs btn-danger delete' } do
21
+ = fa_icon 'trash-alt'
@@ -0,0 +1,19 @@
1
+ - if object.class.show_associations.nil?
2
+ = "Please, fill show associations method in decorator"
3
+ - else
4
+ - if object.class.show_associations.map(&:to_s).include? association.name.to_s
5
+ - association_type = association.class.to_s.split('::').last.sub(/Reflection$/, '').underscore.to_sym
6
+ %tr
7
+ %td
8
+ = model_class.human_attribute_name association.name
9
+ %hr
10
+ - if create_is_available?(association.class_name) && (association_type != :has_one || !object.send(association.name).present?)
11
+ = link_to "#{I18n.t('helpers.actions.add')} #{model_class.human_attribute_name(association.name).singularize.downcase}", new_associated_record_path(association: association, object: object, as: object.send("#{association.name}_as")), class: 'btn btn-primary'
12
+ %td{ colspan: 2 }
13
+ - if association_type.in? [ :has_one, :belongs_to ]
14
+ %table.table.table-striped.table-bordered
15
+ = render 'tramway/shared/show/associations/table_row', object: object, association: association, association_object: object.send(association.name)
16
+ - else
17
+ %table.table.table-striped.table-bordered
18
+ - object.send(association.name)&.each do |association_object|
19
+ = render 'tramway/shared/show/associations/table_row', object: object, association: association, association_object: association_object
@@ -0,0 +1,21 @@
1
+ - if (!association_object.is_a?(Array) || !association_object.empty?) && association_object.present?
2
+ %tr{ id: "#{association.name}_#{association_object.id}" }
3
+ %td
4
+ = association_object.id
5
+ %td
6
+ = link_to association_object.name, record_path(association_object.id, model: association.options[:class_name])
7
+ - if association_object.model.class.state_machines_names.any?
8
+ - state_machine_names = association_object.listed_state_machines || association_object.model.class.state_machines_names
9
+ %td
10
+ - state_machine_names.each do |state_method|
11
+ = state_events_buttons association_object, state_method: state_method, model_param_name: :record, parameters: { redirect: current_model_record_path(object.id), model: association_object.class.model_name }, button_options: { class: :smart_button }
12
+ %td{ style: 'display: flex; justify-content: space-evenly' }
13
+ - if update_is_available? association_object
14
+ = edit_button url: edit_record_path(association_object.id, model: association.options[:class_name], redirect: current_model_record_path(object.id)), button_options: { class: 'btn btn-xs btn-warning edit', style: 'height: max-content' } do
15
+ = fa_icon 'pencil-alt'
16
+ - if destroy_is_available? association_object
17
+ = delete_button url: record_path(association_object.id, model: association.options[:class_name], redirect: current_model_record_path(object.id)), button_options: { class: 'btn btn-xs btn-danger delete' } do
18
+ = fa_icon 'trash-alt'
19
+ - if habtm_destroy_is_available? association_object, object
20
+ = delete_button url: has_and_belongs_to_many_record_path(association_object.id, model_class: object.model.class, object_id: object.id, form: "Admin::#{object.model.class.to_s.pluralize}::Remove#{association_object.model.class.to_s}Form", redirect: current_model_record_path(object.id)), button_options: { class: 'btn btn-xs btn-danger delete' } do
21
+ = fa_icon 'trash-alt'
@@ -0,0 +1,15 @@
1
+ - current_title = page_title(action, model_class)
2
+ - title current_title
3
+ .page-header
4
+ %h1= current_title
5
+ %hr
6
+ .row
7
+ .col-lg-12
8
+ = render 'tramway/shared/messages', object: @singleton_form
9
+ .row
10
+ .col-lg-12
11
+ = simple_form_for @singleton_form.model, url: { controller: :singletons, action: action, model: @singleton_form.model.class }, input_html: { class: 'form-horizontal' } do |f|
12
+ - @singleton_form.properties.each do |property, type|
13
+ = render 'tramway/shared/input', property: property, object: :singleton, type: type, form: f, destination: :admin, value: value_from_params(model_class: model_class, property: property, type: type)
14
+ = f.button :submit, t('helpers.links.save'), class: 'btn btn-success'
15
+ = link_to t('helpers.links.back'), singleton_path, class: 'btn btn-secondary'
@@ -0,0 +1 @@
1
+ = render partial: 'form', locals: { action: :update }
@@ -0,0 +1 @@
1
+ = render partial: 'form', locals: { action: :create }
@@ -0,0 +1 @@
1
+ = render 'tramway/shared/show', object: @singleton
@@ -0,0 +1,4 @@
1
+ - title
2
+ %h1
3
+ = @application&.try(:title) || @application&.public_name
4
+ != @content
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.config.assets.precompile += [
4
+ 'vendor/assets/javascripts/*',
5
+ 'vendor/assets/stylesheets/*',
6
+ 'tramway/admin/ckeditor/*'
7
+ ]
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveSupport.on_load :active_record do
4
+ require 'audited'
5
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ckeditor'
4
+
5
+ Ckeditor.setup do |config|
6
+ require 'ckeditor/orm/active_record'
7
+
8
+ config.assets_plugins = %w[image copyformatting filebrowser sourcedialog]
9
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ {
4
+ ru: {
5
+ i18n: {
6
+ plural: {
7
+ keys: %i[zero one few many],
8
+ rule: lambda do |n|
9
+ if n.zero?
10
+ :zero
11
+ elsif n % 10 == 1 && n % 100 != 11
12
+ # 1, 21, 31, 41, 51, 61...
13
+ :one
14
+ elsif [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100)
15
+ # 2-4, 22-24, 32-34...
16
+ :few
17
+ elsif n % 10.zero? || ![5, 6, 7, 8, 9].include?(n % 10) || ![11, 12, 13, 14].include?(n % 100)
18
+ # 0, 5-20, 25-30, 35-40...
19
+ :many
20
+ end
21
+ end
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,4 @@
1
+ en:
2
+ default:
3
+ collections:
4
+ all: All