From 181af5b433c12d5875a511ed5e38c35ebac15cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Tue, 6 Apr 2021 22:44:39 +0100 Subject: [PATCH 01/21] Remove field instructions --- config/locales/en.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 636da09b..e3514b28 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -125,7 +125,6 @@ en: presenters: Presenters form_presentation_details: delete_confirmation: "Are you sure you want to delete the presentation %{presentation}?" - start_time_instructions: Enter in 24-hour format using a colon as the divider multiple_presenters_selection_instructions_html: "Select multiple presenters by holding for a continuous selection, or, for a discontinous selection, on Mac, or Ctrl on Windows and Linux" From d99620777859f3860fdf6a9637b5084d8fbfac8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Mon, 22 Mar 2021 17:55:42 +0000 Subject: [PATCH 02/21] Refactor controller --- .../spina/admin/conferences/application_controller.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/controllers/spina/admin/conferences/application_controller.rb b/app/controllers/spina/admin/conferences/application_controller.rb index de9bec33..a0dd87ac 100644 --- a/app/controllers/spina/admin/conferences/application_controller.rb +++ b/app/controllers/spina/admin/conferences/application_controller.rb @@ -7,13 +7,7 @@ module Conferences class ApplicationController < ::Spina::Admin::AdminController add_flash_types :success - layout :admin_layout, only: %i[new edit] - - private - - def admin_layout - 'spina/admin/conferences/application' - end + layout 'spina/admin/conferences/application', only: %i[new edit] end end end From b9f25903aabeca147f0542f192842ca625e2455f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Sun, 4 Apr 2021 02:02:46 +0100 Subject: [PATCH 03/21] Isolate namespace But avoid route helper hell by including all the helpers --- .../conferences/application_controller.rb | 2 + .../conferences/conferences_controller.rb | 24 +++++----- .../admin/conferences/delegates_controller.rb | 6 +-- .../dietary_requirements_controller.rb | 2 +- .../conferences/institutions_controller.rb | 2 +- ...resentation_attachment_types_controller.rb | 2 +- .../presentation_types_controller.rb | 2 +- .../conferences/presentations_controller.rb | 7 ++- .../admin/conferences/rooms_controller.rb | 2 +- .../admin/conferences/sessions_controller.rb | 2 +- .../conferences/conferences/_form.html.haml | 2 +- .../conferences/delegates/_form.html.haml | 2 +- .../dietary_requirements/_form.html.haml | 2 +- .../conferences/institutions/_form.html.haml | 2 +- .../_form.html.haml | 2 +- .../presentation_types/_form.html.haml | 2 +- .../conferences/presentations/_form.html.haml | 2 +- .../_form_presentation_details.html.haml | 4 +- .../admin/conferences/rooms/_form.html.haml | 2 +- .../conferences/sessions/_form.html.haml | 2 +- .../sessions/_form_session_details.html.haml | 4 +- lib/spina/admin/conferences/engine.rb | 2 + .../conferences_controller_test.rb | 22 +++++----- .../conferences/delegates_controller_test.rb | 16 +++---- .../dietary_requirements_controller_test.rb | 16 +++---- .../institutions_controller_test.rb | 16 +++---- ...tation_attachment_types_controller_test.rb | 16 +++---- .../presentation_types_controller_test.rb | 16 +++---- .../presentations_controller_test.rb | 16 +++---- .../conferences/rooms_controller_test.rb | 16 +++---- .../conferences/sessions_controller_test.rb | 16 +++---- .../admin/conferences/conferences_test.rb | 44 +++++++++---------- .../spina/admin/conferences/delegates_test.rb | 24 +++++----- .../conferences/dietary_requirements_test.rb | 4 +- .../admin/conferences/institutions_test.rb | 8 ++-- .../presentation_attachment_types_test.rb | 4 +- .../conferences/presentation_types_test.rb | 12 ++--- .../admin/conferences/presentations_test.rb | 36 +++++++-------- .../spina/admin/conferences/rooms_test.rb | 12 ++--- .../spina/admin/conferences/sessions_test.rb | 20 ++++----- 40 files changed, 195 insertions(+), 198 deletions(-) diff --git a/app/controllers/spina/admin/conferences/application_controller.rb b/app/controllers/spina/admin/conferences/application_controller.rb index a0dd87ac..6dc2de13 100644 --- a/app/controllers/spina/admin/conferences/application_controller.rb +++ b/app/controllers/spina/admin/conferences/application_controller.rb @@ -5,6 +5,8 @@ module Admin module Conferences # @abstract Subclass to implement a custom controller. class ApplicationController < ::Spina::Admin::AdminController + helper ::Spina::Engine.routes.url_helpers + add_flash_types :success layout 'spina/admin/conferences/application', only: %i[new edit] diff --git a/app/controllers/spina/admin/conferences/conferences_controller.rb b/app/controllers/spina/admin/conferences/conferences_controller.rb index c9b20b3d..443cdad3 100644 --- a/app/controllers/spina/admin/conferences/conferences_controller.rb +++ b/app/controllers/spina/admin/conferences/conferences_controller.rb @@ -128,19 +128,17 @@ def build_parts end end - def conference_params # rubocop:disable Metrics/MethodLength - params.require(:admin_conferences_conference).permit(:start_date, :finish_date, :name, - events_attributes: - %i[id name start_datetime finish_datetime description location], - parts_attributes: - [:id, :title, :name, :partable_type, :partable_id, - { partable_attributes: - [:id, :content, :image_tokens, :image_positions, :date, :time, - { structure_items_attributes: - [:id, :position, :_destroy, - { structure_parts_attributes: - [:id, :title, :structure_partable_type, :name, :partable_id, - { partable_attributes: {} }] }] }] }]) + def conference_params + params.require(:conference).permit(:start_date, :finish_date, :name, + events_attributes: %i[id name start_datetime finish_datetime description location], + parts_attributes: [:id, :title, :name, :partable_type, :partable_id, + { partable_attributes: + [:id, :content, :image_tokens, :image_positions, :date, :time, + { structure_items_attributes: + [:id, :position, :_destroy, + { structure_parts_attributes: + [:id, :title, :structure_partable_type, :name, :partable_id, + { partable_attributes: {} }] }] }] }]) end end end diff --git a/app/controllers/spina/admin/conferences/delegates_controller.rb b/app/controllers/spina/admin/conferences/delegates_controller.rb index b0daf29c..041c22be 100644 --- a/app/controllers/spina/admin/conferences/delegates_controller.rb +++ b/app/controllers/spina/admin/conferences/delegates_controller.rb @@ -105,10 +105,8 @@ def set_tabs end def delegate_params - params.require(:admin_conferences_delegate).permit(:first_name, :last_name, :email_address, :url, - :institution_id, - conference_ids: [], - dietary_requirement_ids: []) + params.require(:delegate).permit(:first_name, :last_name, :email_address, :url, :institution_id, + conference_ids: [], dietary_requirement_ids: []) end end end diff --git a/app/controllers/spina/admin/conferences/dietary_requirements_controller.rb b/app/controllers/spina/admin/conferences/dietary_requirements_controller.rb index b9e81d27..f24a74d7 100644 --- a/app/controllers/spina/admin/conferences/dietary_requirements_controller.rb +++ b/app/controllers/spina/admin/conferences/dietary_requirements_controller.rb @@ -98,7 +98,7 @@ def set_tabs end def dietary_requirement_params - params.require(:admin_conferences_dietary_requirement).permit(:name) + params.require(:dietary_requirement).permit(:name) end end end diff --git a/app/controllers/spina/admin/conferences/institutions_controller.rb b/app/controllers/spina/admin/conferences/institutions_controller.rb index d8338297..e94b9146 100644 --- a/app/controllers/spina/admin/conferences/institutions_controller.rb +++ b/app/controllers/spina/admin/conferences/institutions_controller.rb @@ -98,7 +98,7 @@ def set_tabs end def conference_params - params.require(:admin_conferences_institution).permit(:name, :city, :logo_id) + params.require(:institution).permit(:name, :city, :logo_id) end end end diff --git a/app/controllers/spina/admin/conferences/presentation_attachment_types_controller.rb b/app/controllers/spina/admin/conferences/presentation_attachment_types_controller.rb index 534da1d5..1ab43907 100644 --- a/app/controllers/spina/admin/conferences/presentation_attachment_types_controller.rb +++ b/app/controllers/spina/admin/conferences/presentation_attachment_types_controller.rb @@ -96,7 +96,7 @@ def set_breadcrumb # noinspection RubyInstanceMethodNamingConvention def presentation_attachment_type_params - params.require(:admin_conferences_presentation_attachment_type).permit(:name) + params.require(:presentation_attachment_type).permit(:name) end end end diff --git a/app/controllers/spina/admin/conferences/presentation_types_controller.rb b/app/controllers/spina/admin/conferences/presentation_types_controller.rb index 6bd93a73..1e864e09 100644 --- a/app/controllers/spina/admin/conferences/presentation_types_controller.rb +++ b/app/controllers/spina/admin/conferences/presentation_types_controller.rb @@ -101,7 +101,7 @@ def set_tabs end def presentation_type_params - params.require(:admin_conferences_presentation_type).permit(:name, :conference_id, :minutes) + params.require(:presentation_type).permit(:name, :conference_id, :minutes) end end end diff --git a/app/controllers/spina/admin/conferences/presentations_controller.rb b/app/controllers/spina/admin/conferences/presentations_controller.rb index 8db7548e..3412e05b 100644 --- a/app/controllers/spina/admin/conferences/presentations_controller.rb +++ b/app/controllers/spina/admin/conferences/presentations_controller.rb @@ -113,10 +113,9 @@ def set_tabs end def presentation_params - params.require(:admin_conferences_presentation).permit(:title, :abstract, :session_id, :start_datetime, - presenter_ids: [], - attachments_attributes: - %i[id attachment_id attachment_type_id _destroy]) + params.require(:presentation).permit(:title, :abstract, :session_id, :start_datetime, + presenter_ids: [], + attachments_attributes: %i[id attachment_id attachment_type_id _destroy]) end end end diff --git a/app/controllers/spina/admin/conferences/rooms_controller.rb b/app/controllers/spina/admin/conferences/rooms_controller.rb index 6c8e448e..15b90c72 100644 --- a/app/controllers/spina/admin/conferences/rooms_controller.rb +++ b/app/controllers/spina/admin/conferences/rooms_controller.rb @@ -101,7 +101,7 @@ def set_tabs end def room_params - params.require(:admin_conferences_room).permit(:building, :number, :institution_id) + params.require(:room).permit(:building, :number, :institution_id) end end end diff --git a/app/controllers/spina/admin/conferences/sessions_controller.rb b/app/controllers/spina/admin/conferences/sessions_controller.rb index 243cecc7..9172c8a2 100644 --- a/app/controllers/spina/admin/conferences/sessions_controller.rb +++ b/app/controllers/spina/admin/conferences/sessions_controller.rb @@ -110,7 +110,7 @@ def set_tabs end def session_params - params.require(:admin_conferences_session).permit(:name, :presentation_type_id, :room_id) + params.require(:session).permit(:name, :presentation_type_id, :room_id) end end end diff --git a/app/views/spina/admin/conferences/conferences/_form.html.haml b/app/views/spina/admin/conferences/conferences/_form.html.haml index 51fdb735..1df36f04 100644 --- a/app/views/spina/admin/conferences/conferences/_form.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @conference.errors -= form_for @conference, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @conference], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/delegates/_form.html.haml b/app/views/spina/admin/conferences/delegates/_form.html.haml index 4f776cb9..670dd875 100644 --- a/app/views/spina/admin/conferences/delegates/_form.html.haml +++ b/app/views/spina/admin/conferences/delegates/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @delegate.errors -= form_for @delegate, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @delegate], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml b/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml index 1daecea5..83f0e361 100644 --- a/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml +++ b/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @dietary_requirement.errors -= form_for @dietary_requirement, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @dietary_requirement], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/institutions/_form.html.haml b/app/views/spina/admin/conferences/institutions/_form.html.haml index 9bbb7c90..f1647518 100644 --- a/app/views/spina/admin/conferences/institutions/_form.html.haml +++ b/app/views/spina/admin/conferences/institutions/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @institution.errors -= form_for @institution, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @institution], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml b/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml index c82d9532..a009e39b 100644 --- a/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml +++ b/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @presentation_attachment_type.errors -= form_for @presentation_attachment_type, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @presentation_attachment_type], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/presentation_types/_form.html.haml b/app/views/spina/admin/conferences/presentation_types/_form.html.haml index d836472b..937bf2b5 100644 --- a/app/views/spina/admin/conferences/presentation_types/_form.html.haml +++ b/app/views/spina/admin/conferences/presentation_types/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @presentation_type.errors -= form_for @presentation_type, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @presentation_type], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/presentations/_form.html.haml b/app/views/spina/admin/conferences/presentations/_form.html.haml index cea13891..42cdc23d 100644 --- a/app/views/spina/admin/conferences/presentations/_form.html.haml +++ b/app/views/spina/admin/conferences/presentations/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @presentation.errors -= form_for @presentation, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @presentation], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml index 19286882..a113d16c 100644 --- a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml +++ b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml @@ -4,13 +4,13 @@ .horizontal-form-group .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :conference .horizontal-form-content - .select-dropdown= select_tag :admin_conferences_conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@presentation.conference.id unless @presentation.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility', 'spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@presentation.conference.id unless @presentation.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility', 'spina--admin--conferences--select_options_target': 'select', text_key: 'name' } .horizontal-form-group .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :session .horizontal-form-content .input-group - .select-dropdown= select_tag :admin_conferences_presentation_type_id, options_from_collection_for_select((@presentation.conference || Spina::Admin::Conferences::Conference.first).presentation_types, :id, :name, (@presentation.presentation_type.id unless @presentation.presentation_type.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types', text_key: 'name' } + .select-dropdown= select_tag :presentation_type_id, options_from_collection_for_select((@presentation.conference || Spina::Admin::Conferences::Conference.first).presentation_types, :id, :name, (@presentation.presentation_type.id unless @presentation.presentation_type.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types', text_key: 'name' } .select-dropdown= f.collection_select :session_id, (@presentation.presentation_type || Spina::Admin::Conferences::Conference.first).sessions, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types:sessions', text_key: 'name' } .horizontal-form-group diff --git a/app/views/spina/admin/conferences/rooms/_form.html.haml b/app/views/spina/admin/conferences/rooms/_form.html.haml index e0ce3bb9..84533b25 100644 --- a/app/views/spina/admin/conferences/rooms/_form.html.haml +++ b/app/views/spina/admin/conferences/rooms/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @room.errors -= form_for @room, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @room], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/sessions/_form.html.haml b/app/views/spina/admin/conferences/sessions/_form.html.haml index 8249a2f8..7603a30c 100644 --- a/app/views/spina/admin/conferences/sessions/_form.html.haml +++ b/app/views/spina/admin/conferences/sessions/_form.html.haml @@ -2,7 +2,7 @@ - content_for :notifications do = render 'errors', errors: @session.errors -= form_for @session, html: { autocomplete: 'off' } do |f| += form_for [:admin_conferences, @session], html: { autocomplete: 'off' } do |f| %header#header = render partial: 'spina/admin/shared/breadcrumbs' diff --git a/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml b/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml index 6a9c68f5..31b23a2d 100644 --- a/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml +++ b/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml @@ -9,14 +9,14 @@ .horizontal-form-label= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type .horizontal-form-content .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } - .select-dropdown= select_tag :admin_conferences_conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@session.conference.id unless @session.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@session.conference.id unless @session.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } .select-dropdown= f.collection_select :presentation_type_id, @session.conference.present? ? @session.conference.presentation_types : Spina::Admin::Conferences::Conference.first.presentation_types, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'presentation_types' } .horizontal-form-group .horizontal-form-label= Spina::Admin::Conferences::Session.human_attribute_name :room .horizontal-form-content .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @institutions } } } - .select-dropdown= select_tag :admin_conferences_institution_id, options_from_collection_for_select(Spina::Admin::Conferences::Institution.all, :id, :name, (@session.institution.id unless @session.institution.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + .select-dropdown= select_tag :institution_id, options_from_collection_for_select(Spina::Admin::Conferences::Institution.all, :id, :name, (@session.institution.id unless @session.institution.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } .select-dropdown= f.collection_select :room_id, @session.institution.present? ? @session.institution.rooms : Spina::Admin::Conferences::Institution.first.rooms, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'rooms' } - unless @session.new_record? diff --git a/lib/spina/admin/conferences/engine.rb b/lib/spina/admin/conferences/engine.rb index d43f365f..18c97acc 100644 --- a/lib/spina/admin/conferences/engine.rb +++ b/lib/spina/admin/conferences/engine.rb @@ -6,6 +6,8 @@ module Conferences # Engine class for the plugin. This is where the plugin is registered as a {Spina::Plugin} with {Spina}. # @note The +name+ and +namespace+ of the {Spina::Plugin} object is +'conferences'+ (for compatibility reasons). class Engine < ::Rails::Engine + isolate_namespace Spina::Admin::Conferences + config.before_initialize do ::Spina::Plugin.register do |plugin| plugin.name = 'conferences' diff --git a/test/controllers/spina/admin/conferences/conferences_controller_test.rb b/test/controllers/spina/admin/conferences/conferences_controller_test.rb index 6918a035..c852b690 100644 --- a/test/controllers/spina/admin/conferences/conferences_controller_test.rb +++ b/test/controllers/spina/admin/conferences/conferences_controller_test.rb @@ -63,7 +63,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:finish_date] = @conference.finish_date attributes[:name] = @conference.name assert_difference 'Conference.count' do - post admin_conferences_conferences_url, params: { admin_conferences_conference: attributes } + post admin_conferences_conferences_url, params: { conference: attributes } end assert_redirected_to admin_conferences_conferences_url assert_equal 'Conference saved', flash[:success] @@ -75,7 +75,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:finish_date] = @conference.finish_date attributes[:name] = @conference.name assert_difference 'Conference.count' do - post admin_conferences_conferences_url, params: { admin_conferences_conference: attributes }, as: :turbo_stream + post admin_conferences_conferences_url, params: { conference: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_conferences_url assert_equal 'Conference saved', flash[:success] @@ -87,7 +87,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:finish_date] = @invalid_conference.finish_date attributes[:name] = @invalid_conference.name assert_no_difference 'Conference.count' do - post admin_conferences_conferences_url, params: { admin_conferences_conference: attributes } + post admin_conferences_conferences_url, params: { conference: attributes } end assert_response :success assert_not_equal 'Conference saved', flash[:success] @@ -99,7 +99,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:finish_date] = @invalid_conference.finish_date attributes[:name] = @invalid_conference.name assert_no_difference 'Conference.count' do - post admin_conferences_conferences_url, params: { admin_conferences_conference: attributes }, as: :turbo_stream + post admin_conferences_conferences_url, params: { conference: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Conference saved', flash[:success] @@ -110,7 +110,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:start_date] = @conference.start_date attributes[:finish_date] = @conference.finish_date attributes[:name] = @conference.name - patch admin_conferences_conference_url(@conference), params: { admin_conferences_conference: attributes } + patch admin_conferences_conference_url(@conference), params: { conference: attributes } assert_redirected_to admin_conferences_conferences_url assert_equal 'Conference saved', flash[:success] end @@ -120,7 +120,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:start_date] = @conference.start_date attributes[:finish_date] = @conference.finish_date attributes[:name] = @conference.name - patch admin_conferences_conference_url(@conference), params: { admin_conferences_conference: attributes }, as: :turbo_stream + patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_conferences_url assert_equal 'Conference saved', flash[:success] end @@ -130,7 +130,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:start_date] = @invalid_conference.start_date attributes[:finish_date] = @invalid_conference.finish_date attributes[:name] = @invalid_conference.name - patch admin_conferences_conference_url(@conference), params: { admin_conferences_conference: attributes } + patch admin_conferences_conference_url(@conference), params: { conference: attributes } assert_response :success assert_not_equal 'Conference saved', flash[:success] end @@ -140,7 +140,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:start_date] = @invalid_conference.start_date attributes[:finish_date] = @invalid_conference.finish_date attributes[:name] = @invalid_conference.name - patch admin_conferences_conference_url(@conference), params: { admin_conferences_conference: attributes }, as: :turbo_stream + patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Conference saved', flash[:success] end @@ -186,7 +186,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:parts_attributes].find { |part| part['name'] == 'submission_text' } .then { |part| part['partable_attributes']['content'] = 'Dolor sit amen' } assert_changes -> { @conference.content('submission_text') }, from: 'Lorem ipsum dolor sit amet', to: 'Dolor sit amen' do - patch admin_conferences_conference_url(@conference), params: { admin_conferences_conference: attributes }, as: :turbo_stream + patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream end end @@ -212,7 +212,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa end assert_changes -> { @conference.content('sponsors').structure_items.first.content('name') }, from: 'Lorem ipsum dolor sit amet', to: 'Test' do - patch admin_conferences_conference_url(@conference), params: { admin_conferences_conference: attributes }, as: :turbo_stream + patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream end end @@ -239,7 +239,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa end assert_changes -> { @conference.content('sponsors').structure_items.first.content('logo') }, from: @dubrovnik_image, to: @rovinj_image do - patch admin_conferences_conference_url(@conference), params: { admin_conferences_conference: attributes }, as: :turbo_stream + patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream end end diff --git a/test/controllers/spina/admin/conferences/delegates_controller_test.rb b/test/controllers/spina/admin/conferences/delegates_controller_test.rb index 2ccb2d9d..9894c76d 100644 --- a/test/controllers/spina/admin/conferences/delegates_controller_test.rb +++ b/test/controllers/spina/admin/conferences/delegates_controller_test.rb @@ -46,7 +46,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl attributes = @delegate.attributes attributes[:conference_ids] = @delegate.conference_ids assert_difference 'Delegate.count' do - post admin_conferences_delegates_url, params: { admin_conferences_delegate: attributes } + post admin_conferences_delegates_url, params: { delegate: attributes } end assert_redirected_to admin_conferences_delegates_url assert_equal 'Delegate saved', flash[:success] @@ -56,7 +56,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl attributes = @delegate.attributes attributes[:conference_ids] = @delegate.conference_ids assert_difference 'Delegate.count' do - post admin_conferences_delegates_url, params: { admin_conferences_delegate: attributes }, as: :turbo_stream + post admin_conferences_delegates_url, params: { delegate: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_delegates_url assert_equal 'Delegate saved', flash[:success] @@ -66,7 +66,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl attributes = @invalid_delegate.attributes attributes[:conference_ids] = @invalid_delegate.conference_ids assert_no_difference 'Delegate.count' do - post admin_conferences_delegates_url, params: { admin_conferences_delegate: attributes } + post admin_conferences_delegates_url, params: { delegate: attributes } end assert_response :success assert_not_equal 'Delegate saved', flash[:success] @@ -76,7 +76,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl attributes = @invalid_delegate.attributes attributes[:conference_ids] = @invalid_delegate.conference_ids assert_no_difference 'Delegate.count' do - post admin_conferences_delegates_url, params: { admin_conferences_delegate: attributes }, as: :turbo_stream + post admin_conferences_delegates_url, params: { delegate: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Delegate saved', flash[:success] @@ -85,7 +85,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl test 'should update delegate' do attributes = @delegate.attributes attributes[:conference_ids] = @delegate.conference_ids - patch admin_conferences_delegate_url(@delegate), params: { admin_conferences_delegate: attributes } + patch admin_conferences_delegate_url(@delegate), params: { delegate: attributes } assert_redirected_to admin_conferences_delegates_url assert_equal 'Delegate saved', flash[:success] end @@ -93,7 +93,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl test 'should update delegate with remote form' do attributes = @delegate.attributes attributes[:conference_ids] = @delegate.conference_ids - patch admin_conferences_delegate_url(@delegate), params: { admin_conferences_delegate: attributes }, + patch admin_conferences_delegate_url(@delegate), params: { delegate: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_delegates_url assert_equal 'Delegate saved', flash[:success] @@ -102,7 +102,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl test 'should fail to update invalid delegate' do attributes = @invalid_delegate.attributes attributes[:conference_ids] = @invalid_delegate.conference_ids - patch admin_conferences_delegate_url(@delegate), params: { admin_conferences_delegate: attributes } + patch admin_conferences_delegate_url(@delegate), params: { delegate: attributes } assert_response :success assert_not_equal 'Delegate saved', flash[:success] end @@ -110,7 +110,7 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl test 'should fail to update invalid delegate with remote form' do attributes = @invalid_delegate.attributes attributes[:conference_ids] = @invalid_delegate.conference_ids - patch admin_conferences_delegate_url(@delegate), params: { admin_conferences_delegate: attributes }, as: :turbo_stream + patch admin_conferences_delegate_url(@delegate), params: { delegate: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Delegate saved', flash[:success] end diff --git a/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb b/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb index 964fc4f6..c89a3811 100644 --- a/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb +++ b/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb @@ -41,7 +41,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @dietary_requirement.attributes attributes[:name] = @dietary_requirement.name assert_difference 'DietaryRequirement.count' do - post admin_conferences_dietary_requirements_url, params: { admin_conferences_dietary_requirement: attributes } + post admin_conferences_dietary_requirements_url, params: { dietary_requirement: attributes } end assert_redirected_to admin_conferences_dietary_requirements_url assert_equal 'Dietary requirement saved', flash[:success] @@ -51,7 +51,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @dietary_requirement.attributes attributes[:name] = @dietary_requirement.name assert_difference 'DietaryRequirement.count' do - post admin_conferences_dietary_requirements_url, params: { admin_conferences_dietary_requirement: attributes }, as: :turbo_stream + post admin_conferences_dietary_requirements_url, params: { dietary_requirement: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_dietary_requirements_url assert_equal 'Dietary requirement saved', flash[:success] @@ -61,7 +61,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @invalid_dietary_requirement.attributes attributes[:name] = @invalid_dietary_requirement.name assert_no_difference 'DietaryRequirement.count' do - post admin_conferences_dietary_requirements_url, params: { admin_conferences_dietary_requirement: attributes } + post admin_conferences_dietary_requirements_url, params: { dietary_requirement: attributes } end assert_response :success assert_not_equal 'Dietary requirement saved', flash[:success] @@ -71,7 +71,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @invalid_dietary_requirement.attributes attributes[:name] = @invalid_dietary_requirement.name assert_no_difference 'DietaryRequirement.count' do - post admin_conferences_dietary_requirements_url, params: { admin_conferences_dietary_requirement: attributes }, as: :turbo_stream + post admin_conferences_dietary_requirements_url, params: { dietary_requirement: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Dietary requirement saved', flash[:success] @@ -81,7 +81,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @dietary_requirement.attributes attributes[:name] = @dietary_requirement.name patch admin_conferences_dietary_requirement_url(@dietary_requirement), - params: { admin_conferences_dietary_requirement: attributes } + params: { dietary_requirement: attributes } assert_redirected_to admin_conferences_dietary_requirements_url assert_equal 'Dietary requirement saved', flash[:success] end @@ -90,7 +90,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @dietary_requirement.attributes attributes[:name] = @dietary_requirement.name patch admin_conferences_dietary_requirement_url(@dietary_requirement), - params: { admin_conferences_dietary_requirement: attributes }, as: :turbo_stream + params: { dietary_requirement: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_dietary_requirements_url assert_equal 'Dietary requirement saved', flash[:success] end @@ -99,7 +99,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @invalid_dietary_requirement.attributes attributes[:name] = @invalid_dietary_requirement.name patch admin_conferences_dietary_requirement_url(@dietary_requirement), - params: { admin_conferences_dietary_requirement: attributes } + params: { dietary_requirement: attributes } assert_response :success assert_not_equal 'Dietary requirement saved', flash[:success] end @@ -108,7 +108,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo attributes = @invalid_dietary_requirement.attributes attributes[:name] = @invalid_dietary_requirement.name patch admin_conferences_dietary_requirement_url(@dietary_requirement), - params: { admin_conferences_dietary_requirement: attributes }, as: :turbo_stream + params: { dietary_requirement: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Dietary requirement saved', flash[:success] end diff --git a/test/controllers/spina/admin/conferences/institutions_controller_test.rb b/test/controllers/spina/admin/conferences/institutions_controller_test.rb index b3ed9a1b..f484970b 100644 --- a/test/controllers/spina/admin/conferences/institutions_controller_test.rb +++ b/test/controllers/spina/admin/conferences/institutions_controller_test.rb @@ -48,7 +48,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes[:name] = @institution.name attributes[:city] = @institution.city assert_difference 'Institution.count' do - post admin_conferences_institutions_url, params: { admin_conferences_institution: attributes } + post admin_conferences_institutions_url, params: { institution: attributes } end assert_redirected_to admin_conferences_institutions_url assert_equal 'Institution saved', flash[:success] @@ -59,7 +59,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes[:name] = @institution.name attributes[:city] = @institution.city assert_difference 'Institution.count' do - post admin_conferences_institutions_url, params: { admin_conferences_institution: attributes }, as: :turbo_stream + post admin_conferences_institutions_url, params: { institution: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_institutions_url assert_equal 'Institution saved', flash[:success] @@ -70,7 +70,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes[:name] = @invalid_institution.name attributes[:city] = @invalid_institution.city assert_no_difference 'Institution.count' do - post admin_conferences_institutions_url, params: { admin_conferences_institution: attributes } + post admin_conferences_institutions_url, params: { institution: attributes } end assert_response :success assert_not_equal 'Institution saved', flash[:success] @@ -81,7 +81,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes[:name] = @invalid_institution.name attributes[:city] = @invalid_institution.city assert_no_difference 'Institution.count' do - post admin_conferences_institutions_url, params: { admin_conferences_institution: attributes }, as: :turbo_stream + post admin_conferences_institutions_url, params: { institution: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Institution saved', flash[:success] @@ -91,7 +91,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes = @institution.attributes attributes[:name] = @institution.name attributes[:city] = @institution.city - patch admin_conferences_institution_url(@institution), params: { admin_conferences_institution: attributes } + patch admin_conferences_institution_url(@institution), params: { institution: attributes } assert_redirected_to admin_conferences_institutions_url assert_equal 'Institution saved', flash[:success] end @@ -100,7 +100,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes = @institution.attributes attributes[:name] = @institution.name attributes[:city] = @institution.city - patch admin_conferences_institution_url(@institution), params: { admin_conferences_institution: attributes }, as: :turbo_stream + patch admin_conferences_institution_url(@institution), params: { institution: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_institutions_url assert_equal 'Institution saved', flash[:success] end @@ -109,7 +109,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes = @invalid_institution.attributes attributes[:name] = @invalid_institution.name attributes[:city] = @invalid_institution.city - patch admin_conferences_institution_url(@institution), params: { admin_conferences_institution: attributes } + patch admin_conferences_institution_url(@institution), params: { institution: attributes } assert_response :success assert_not_equal 'Institution saved', flash[:success] end @@ -118,7 +118,7 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis attributes = @invalid_institution.attributes attributes[:name] = @invalid_institution.name attributes[:city] = @invalid_institution.city - patch admin_conferences_institution_url(@institution), params: { admin_conferences_institution: attributes }, as: :turbo_stream + patch admin_conferences_institution_url(@institution), params: { institution: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Institution saved', flash[:success] end diff --git a/test/controllers/spina/admin/conferences/presentation_attachment_types_controller_test.rb b/test/controllers/spina/admin/conferences/presentation_attachment_types_controller_test.rb index 30637805..40dda5e5 100644 --- a/test/controllers/spina/admin/conferences/presentation_attachment_types_controller_test.rb +++ b/test/controllers/spina/admin/conferences/presentation_attachment_types_controller_test.rb @@ -35,7 +35,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes = @presentation_attachment_type.attributes attributes[:name] = @presentation_attachment_type.name assert_difference 'PresentationAttachmentType.count' do - post admin_conferences_presentation_attachment_types_url, params: { admin_conferences_presentation_attachment_type: attributes } + post admin_conferences_presentation_attachment_types_url, params: { presentation_attachment_type: attributes } end assert_redirected_to admin_conferences_presentation_attachment_types_url assert_equal 'Presentation attachment type saved', flash[:success] @@ -46,7 +46,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes[:name] = @presentation_attachment_type.name assert_difference 'PresentationAttachmentType.count' do post admin_conferences_presentation_attachment_types_url, - params: { admin_conferences_presentation_attachment_type: attributes }, as: :turbo_stream + params: { presentation_attachment_type: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_presentation_attachment_types_url assert_equal 'Presentation attachment type saved', flash[:success] @@ -56,7 +56,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes = @invalid_presentation_attachment_type.attributes attributes[:name] = @invalid_presentation_attachment_type.name assert_no_difference 'PresentationAttachmentType.count' do - post admin_conferences_presentation_attachment_types_url, params: { admin_conferences_presentation_attachment_type: attributes } + post admin_conferences_presentation_attachment_types_url, params: { presentation_attachment_type: attributes } end assert_response :success assert_not_equal 'Presentation attachment type saved', flash[:success] @@ -67,7 +67,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes[:name] = @invalid_presentation_attachment_type.name assert_no_difference 'PresentationAttachmentType.count' do post admin_conferences_presentation_attachment_types_url, - params: { admin_conferences_presentation_attachment_type: attributes }, as: :turbo_stream + params: { presentation_attachment_type: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Presentation attachment type saved', flash[:success] @@ -77,7 +77,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes = @presentation_attachment_type.attributes attributes[:name] = @presentation_attachment_type.name patch admin_conferences_presentation_attachment_type_url(@presentation_attachment_type), - params: { admin_conferences_presentation_attachment_type: attributes } + params: { presentation_attachment_type: attributes } assert_redirected_to admin_conferences_presentation_attachment_types_url assert_equal 'Presentation attachment type saved', flash[:success] end @@ -86,7 +86,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes = @presentation_attachment_type.attributes attributes[:name] = @presentation_attachment_type.name patch admin_conferences_presentation_attachment_type_url(@presentation_attachment_type), - params: { admin_conferences_presentation_attachment_type: attributes }, as: :turbo_stream + params: { presentation_attachment_type: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_presentation_attachment_types_url assert_equal 'Presentation attachment type saved', flash[:success] end @@ -95,7 +95,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes = @invalid_presentation_attachment_type.attributes attributes[:name] = @invalid_presentation_attachment_type.name patch admin_conferences_presentation_attachment_type_url(@presentation_attachment_type), - params: { admin_conferences_presentation_attachment_type: attributes } + params: { presentation_attachment_type: attributes } assert_response :success assert_not_equal 'Presentation attachment type saved', flash[:success] end @@ -104,7 +104,7 @@ class PresentationAttachmentTypesControllerTest < ActionDispatch::IntegrationTes attributes = @invalid_presentation_attachment_type.attributes attributes[:name] = @invalid_presentation_attachment_type.name patch admin_conferences_presentation_attachment_type_url(@presentation_attachment_type), - params: { admin_conferences_presentation_attachment_type: attributes }, as: :turbo_stream + params: { presentation_attachment_type: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Presentation attachment type saved', flash[:success] end diff --git a/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb b/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb index 1a68d195..76af65be 100644 --- a/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb +++ b/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb @@ -43,7 +43,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes[:minutes] = @presentation_type.minutes attributes[:name] = @presentation_type.name assert_difference 'PresentationType.count' do - post admin_conferences_presentation_types_url, params: { admin_conferences_presentation_type: attributes } + post admin_conferences_presentation_types_url, params: { presentation_type: attributes } end assert_redirected_to admin_conferences_presentation_types_url assert_equal 'Presentation type saved', flash[:success] @@ -54,7 +54,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes[:minutes] = @presentation_type.minutes attributes[:name] = @presentation_type.name assert_difference 'PresentationType.count' do - post admin_conferences_presentation_types_url, params: { admin_conferences_presentation_type: attributes }, as: :turbo_stream + post admin_conferences_presentation_types_url, params: { presentation_type: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_presentation_types_url assert_equal 'Presentation type saved', flash[:success] @@ -65,7 +65,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes[:minutes] = @invalid_presentation_type.minutes attributes[:name] = @invalid_presentation_type.name assert_no_difference 'PresentationType.count' do - post admin_conferences_presentation_types_url, params: { admin_conferences_presentation_type: attributes } + post admin_conferences_presentation_types_url, params: { presentation_type: attributes } end assert_response :success assert_not_equal 'Presentation type saved', flash[:success] @@ -76,7 +76,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes[:minutes] = @invalid_presentation_type.minutes attributes[:name] = @invalid_presentation_type.name assert_no_difference 'PresentationType.count' do - post admin_conferences_presentation_types_url, params: { admin_conferences_presentation_type: attributes }, as: :turbo_stream + post admin_conferences_presentation_types_url, params: { presentation_type: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Presentation type saved', flash[:success] @@ -86,7 +86,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes = @presentation_type.attributes attributes[:minutes] = @presentation_type.minutes attributes[:name] = @presentation_type.name - patch admin_conferences_presentation_type_url(@presentation_type), params: { admin_conferences_presentation_type: attributes } + patch admin_conferences_presentation_type_url(@presentation_type), params: { presentation_type: attributes } assert_redirected_to admin_conferences_presentation_types_url assert_equal 'Presentation type saved', flash[:success] end @@ -96,7 +96,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes[:minutes] = @presentation_type.minutes attributes[:name] = @presentation_type.name patch admin_conferences_presentation_type_url(@presentation_type), - params: { admin_conferences_presentation_type: attributes }, as: :turbo_stream + params: { presentation_type: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_presentation_types_url assert_equal 'Presentation type saved', flash[:success] end @@ -105,7 +105,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes = @invalid_presentation_type.attributes attributes[:minutes] = @invalid_presentation_type.minutes attributes[:name] = @invalid_presentation_type.name - patch admin_conferences_presentation_type_url(@presentation_type), params: { admin_conferences_presentation_type: attributes } + patch admin_conferences_presentation_type_url(@presentation_type), params: { presentation_type: attributes } assert_response :success assert_not_equal 'Presentation type saved', flash[:success] end @@ -115,7 +115,7 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco attributes[:minutes] = @invalid_presentation_type.minutes attributes[:name] = @invalid_presentation_type.name patch admin_conferences_presentation_type_url(@presentation_type), - params: { admin_conferences_presentation_type: attributes }, as: :turbo_stream + params: { presentation_type: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Presentation type saved', flash[:success] end diff --git a/test/controllers/spina/admin/conferences/presentations_controller_test.rb b/test/controllers/spina/admin/conferences/presentations_controller_test.rb index da2c214d..8287ed75 100644 --- a/test/controllers/spina/admin/conferences/presentations_controller_test.rb +++ b/test/controllers/spina/admin/conferences/presentations_controller_test.rb @@ -45,7 +45,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:title] = @presentation.title attributes[:abstract] = @presentation.abstract assert_difference 'Presentation.count' do - post admin_conferences_presentations_url, params: { admin_conferences_presentation: attributes } + post admin_conferences_presentations_url, params: { presentation: attributes } end assert_redirected_to admin_conferences_presentations_url assert_equal 'Presentation saved', flash[:success] @@ -59,7 +59,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:title] = @presentation.title attributes[:abstract] = @presentation.abstract assert_difference 'Presentation.count' do - post admin_conferences_presentations_url, params: { admin_conferences_presentation: attributes }, as: :turbo_stream + post admin_conferences_presentations_url, params: { presentation: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_presentations_url assert_equal 'Presentation saved', flash[:success] @@ -73,7 +73,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:title] = @invalid_presentation.title attributes[:abstract] = @invalid_presentation.abstract assert_no_difference 'Presentation.count' do - post admin_conferences_presentations_url, params: { admin_conferences_presentation: attributes } + post admin_conferences_presentations_url, params: { presentation: attributes } end assert_response :success assert_not_equal 'Presentation saved', flash[:success] @@ -87,7 +87,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:title] = @invalid_presentation.title attributes[:abstract] = @invalid_presentation.abstract assert_no_difference 'Presentation.count' do - post admin_conferences_presentations_url, params: { admin_conferences_presentation: attributes }, as: :turbo_stream + post admin_conferences_presentations_url, params: { presentation: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Presentation saved', flash[:success] @@ -100,7 +100,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:date] = @presentation.date attributes[:title] = @presentation.title attributes[:abstract] = @presentation.abstract - patch admin_conferences_presentation_url(@presentation), params: { admin_conferences_presentation: attributes } + patch admin_conferences_presentation_url(@presentation), params: { presentation: attributes } assert_redirected_to admin_conferences_presentations_url assert_equal 'Presentation saved', flash[:success] end @@ -112,7 +112,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:date] = @presentation.date attributes[:title] = @presentation.title attributes[:abstract] = @presentation.abstract - patch admin_conferences_presentation_url(@presentation), params: { admin_conferences_presentation: attributes }, as: :turbo_stream + patch admin_conferences_presentation_url(@presentation), params: { presentation: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_presentations_url assert_equal 'Presentation saved', flash[:success] end @@ -124,7 +124,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:date] = @invalid_presentation.date attributes[:title] = @invalid_presentation.title attributes[:abstract] = @invalid_presentation.abstract - patch admin_conferences_presentation_url(@presentation), params: { admin_conferences_presentation: attributes } + patch admin_conferences_presentation_url(@presentation), params: { presentation: attributes } assert_response :success assert_not_equal 'Presentation saved', flash[:success] end @@ -136,7 +136,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di attributes[:date] = @invalid_presentation.date attributes[:title] = @invalid_presentation.title attributes[:abstract] = @invalid_presentation.abstract - patch admin_conferences_presentation_url(@presentation), params: { admin_conferences_presentation: attributes }, as: :turbo_stream + patch admin_conferences_presentation_url(@presentation), params: { presentation: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Presentation saved', flash[:success] end diff --git a/test/controllers/spina/admin/conferences/rooms_controller_test.rb b/test/controllers/spina/admin/conferences/rooms_controller_test.rb index 5b7e2150..f940eb31 100644 --- a/test/controllers/spina/admin/conferences/rooms_controller_test.rb +++ b/test/controllers/spina/admin/conferences/rooms_controller_test.rb @@ -42,7 +42,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes[:building] = @room.building attributes[:number] = @room.number assert_difference 'Room.count' do - post admin_conferences_rooms_url, params: { admin_conferences_room: attributes } + post admin_conferences_rooms_url, params: { room: attributes } end assert_redirected_to admin_conferences_rooms_url assert_equal 'Room saved', flash[:success] @@ -53,7 +53,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes[:building] = @room.building attributes[:number] = @room.number assert_difference 'Room.count' do - post admin_conferences_rooms_url, params: { admin_conferences_room: attributes }, as: :turbo_stream + post admin_conferences_rooms_url, params: { room: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_rooms_url assert_equal 'Room saved', flash[:success] @@ -64,7 +64,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes[:building] = @invalid_room.building attributes[:number] = @invalid_room.number assert_no_difference 'Room.count' do - post admin_conferences_rooms_url, params: { admin_conferences_room: attributes } + post admin_conferences_rooms_url, params: { room: attributes } end assert_response :success assert_not_equal 'Room saved', flash[:success] @@ -75,7 +75,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes[:building] = @invalid_room.building attributes[:number] = @invalid_room.number assert_no_difference 'Room.count' do - post admin_conferences_rooms_url, params: { admin_conferences_room: attributes }, as: :turbo_stream + post admin_conferences_rooms_url, params: { room: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Room saved', flash[:success] @@ -85,7 +85,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes = @room.attributes attributes[:building] = @room.building attributes[:number] = @room.number - patch admin_conferences_room_url(@room), params: { admin_conferences_room: attributes } + patch admin_conferences_room_url(@room), params: { room: attributes } assert_redirected_to admin_conferences_rooms_url assert_equal 'Room saved', flash[:success] end @@ -94,7 +94,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes = @room.attributes attributes[:building] = @room.building attributes[:number] = @room.number - patch admin_conferences_room_url(@room), params: { admin_conferences_room: attributes }, as: :turbo_stream + patch admin_conferences_room_url(@room), params: { room: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_rooms_url assert_equal 'Room saved', flash[:success] end @@ -103,7 +103,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes = @invalid_room.attributes attributes[:building] = @invalid_room.building attributes[:number] = @invalid_room.number - patch admin_conferences_room_url(@room), params: { admin_conferences_room: attributes } + patch admin_conferences_room_url(@room), params: { room: attributes } assert_response :success assert_not_equal 'Room saved', flash[:success] end @@ -112,7 +112,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me attributes = @invalid_room.attributes attributes[:building] = @invalid_room.building attributes[:number] = @invalid_room.number - patch admin_conferences_room_url(@room), params: { admin_conferences_room: attributes }, as: :turbo_stream + patch admin_conferences_room_url(@room), params: { room: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Room saved', flash[:success] end diff --git a/test/controllers/spina/admin/conferences/sessions_controller_test.rb b/test/controllers/spina/admin/conferences/sessions_controller_test.rb index 3555f188..702b6bef 100644 --- a/test/controllers/spina/admin/conferences/sessions_controller_test.rb +++ b/test/controllers/spina/admin/conferences/sessions_controller_test.rb @@ -41,7 +41,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable attributes = @session.attributes attributes[:name] = @session.name assert_difference 'Session.count' do - post admin_conferences_sessions_url, params: { admin_conferences_session: attributes } + post admin_conferences_sessions_url, params: { session: attributes } end assert_redirected_to admin_conferences_sessions_url assert_equal 'Session saved', flash[:success] @@ -51,7 +51,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable attributes = @session.attributes attributes[:name] = @session.name assert_difference 'Session.count' do - post admin_conferences_sessions_url, params: { admin_conferences_session: attributes }, as: :turbo_stream + post admin_conferences_sessions_url, params: { session: attributes }, as: :turbo_stream end assert_redirected_to admin_conferences_sessions_url assert_equal 'Session saved', flash[:success] @@ -61,7 +61,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable attributes = @invalid_session.attributes attributes[:name] = @invalid_session.name assert_no_difference 'Session.count' do - post admin_conferences_sessions_url, params: { admin_conferences_session: attributes } + post admin_conferences_sessions_url, params: { session: attributes } end assert_response :success assert_not_equal 'Session saved', flash[:success] @@ -71,7 +71,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable attributes = @invalid_session.attributes attributes[:name] = @invalid_session.name assert_no_difference 'Session.count' do - post admin_conferences_sessions_url, params: { admin_conferences_session: attributes }, as: :turbo_stream + post admin_conferences_sessions_url, params: { session: attributes }, as: :turbo_stream end assert_response :success assert_not_equal 'Session saved', flash[:success] @@ -80,7 +80,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable test 'should update session' do attributes = @session.attributes attributes[:name] = @session.name - patch admin_conferences_session_url(@session), params: { admin_conferences_session: attributes } + patch admin_conferences_session_url(@session), params: { session: attributes } assert_redirected_to admin_conferences_sessions_url assert_equal 'Session saved', flash[:success] end @@ -88,7 +88,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable test 'should update session with remote form' do attributes = @session.attributes attributes[:name] = @session.name - patch admin_conferences_session_url(@session), params: { admin_conferences_session: attributes }, as: :turbo_stream + patch admin_conferences_session_url(@session), params: { session: attributes }, as: :turbo_stream assert_redirected_to admin_conferences_sessions_url assert_equal 'Session saved', flash[:success] end @@ -96,7 +96,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable test 'should fail to update invalid session' do attributes = @invalid_session.attributes attributes[:name] = @invalid_session.name - patch admin_conferences_session_url(@session), params: { admin_conferences_session: attributes } + patch admin_conferences_session_url(@session), params: { session: attributes } assert_response :success assert_not_equal 'Session saved', flash[:success] end @@ -104,7 +104,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable test 'should fail to update invalid session with remote form' do attributes = @invalid_session.attributes attributes[:name] = @invalid_session.name - patch admin_conferences_session_url(@session), params: { admin_conferences_session: attributes }, as: :turbo_stream + patch admin_conferences_session_url(@session), params: { session: attributes }, as: :turbo_stream assert_response :success assert_not_equal 'Session saved', flash[:success] end diff --git a/test/system/spina/admin/conferences/conferences_test.rb b/test/system/spina/admin/conferences/conferences_test.rb index ab8d7f2b..1ece582f 100644 --- a/test/system/spina/admin/conferences/conferences_test.rb +++ b/test/system/spina/admin/conferences/conferences_test.rb @@ -32,18 +32,18 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas assert_selector '.breadcrumbs' do assert_text 'New conference' end - fill_in 'admin_conferences_conference_name', with: @conference.name - fill_in 'admin_conferences_conference_start_date', with: @conference.start_date - fill_in 'admin_conferences_conference_finish_date', with: @conference.finish_date - within '.admin_conferences_event' do + fill_in 'conference_name', with: @conference.name + fill_in 'conference_start_date', with: @conference.start_date + fill_in 'conference_finish_date', with: @conference.finish_date + within '.event' do click_link class: %w[button button-link icon] within '#structure_form_pane_0' do - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_name/, with: @conference.events.first.name - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_start_datetime/, + fill_in id: /conference_events_attributes_[0-9]_name/, with: @conference.events.first.name + fill_in id: /conference_events_attributes_[0-9]_start_datetime/, with: @conference.events.first.start_datetime - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_finish_datetime/, - with: @conference.events.first.finish_datetime - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_location/, with: @conference.events.first.location + fill_in id: /conference_events_attributes_[0-9]_finish_datetime/, + with: @conference.events.first.finish_datetime + fill_in id: /conference_events_attributes_[0-9]_location/, with: @conference.events.first.location fill_in_rich_text_area with: @conference.events.first.description end end @@ -76,11 +76,11 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas within '[data-name="sponsors"]' do click_link class: %w[button button-link] within id: /structure_form_pane_[0-9]+/ do - fill_in id: /admin_conferences_conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ + fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ _structure_parts_attributes_0_partable_attributes_content/x, with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts.find_by(name: 'name') .partable.content - fill_in id: /admin_conferences_conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ + fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ _structure_parts_attributes_2_partable_attributes_content/x, with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts .find_by(name: 'website').partable.content @@ -107,21 +107,19 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas assert_text @conference.name end Percy.snapshot page, name: 'Conferences form on update' - fill_in 'admin_conferences_conference_name', with: @conference.name - fill_in 'admin_conferences_conference_start_date', with: @conference.start_date - fill_in 'admin_conferences_conference_finish_date', with: @conference.finish_date - within '.admin_conferences_event' do + fill_in 'conference_name', with: @conference.name + fill_in 'conference_start_date', with: @conference.start_date + fill_in 'conference_finish_date', with: @conference.finish_date + within '.event' do click_link class: %w[button button-link icon] within '.structure-form-menu ul' do click_link href: '#structure_form_pane_1' end within '#structure_form_pane_1' do - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_name/, with: @conference.events.first.name - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_start_datetime/, - with: @conference.events.first.start_datetime - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_finish_datetime/, - with: @conference.events.first.finish_datetime - fill_in id: /admin_conferences_conference_events_attributes_[0-9]_location/, with: @conference.events.first.location + fill_in id: /conference_events_attributes_[0-9]_name/, with: @conference.events.first.name + fill_in id: /conference_events_attributes_[0-9]_start_datetime/, with: @conference.events.first.start_datetime + fill_in id: /conference_events_attributes_[0-9]_finish_datetime/, with: @conference.events.first.finish_datetime + fill_in id: /conference_events_attributes_[0-9]_location/, with: @conference.events.first.location fill_in_rich_text_area with: @conference.events.first.description end end @@ -152,11 +150,11 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas assert_no_selector '#overlay' within '[data-name="sponsors"]' do within id: /structure_form_pane_[0-9]+/ do - fill_in id: /admin_conferences_conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ + fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ _structure_parts_attributes_0_partable_attributes_content/x, with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts.find_by(name: 'name') .partable.content - fill_in id: /admin_conferences_conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ + fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ _structure_parts_attributes_2_partable_attributes_content/x, with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts .find_by(name: 'website').partable.content diff --git a/test/system/spina/admin/conferences/delegates_test.rb b/test/system/spina/admin/conferences/delegates_test.rb index fd7873e2..e67eaef6 100644 --- a/test/system/spina/admin/conferences/delegates_test.rb +++ b/test/system/spina/admin/conferences/delegates_test.rb @@ -31,13 +31,13 @@ class DelegatesTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text 'New delegate' end - fill_in 'admin_conferences_delegate_first_name', with: @delegate.first_name - fill_in 'admin_conferences_delegate_last_name', with: @delegate.last_name - select @delegate.institution.name, from: 'admin_conferences_delegate_institution_id' - fill_in 'admin_conferences_delegate_email_address', with: @delegate.email_address - fill_in 'admin_conferences_delegate_url', with: @delegate.url + fill_in 'delegate_first_name', with: @delegate.first_name + fill_in 'delegate_last_name', with: @delegate.last_name + select @delegate.institution.name, from: 'delegate_institution_id' + fill_in 'delegate_email_address', with: @delegate.email_address + fill_in 'delegate_url', with: @delegate.url @delegate - .conferences.each { |conference| select conference.name, from: 'admin_conferences_delegate_conference_ids' } + .conferences.each { |conference| select conference.name, from: 'delegate_conference_ids' } Percy.snapshot page, name: 'Delegates form on create' click_on 'Save delegate' assert_text 'Delegate saved' @@ -53,13 +53,13 @@ class DelegatesTest < ApplicationSystemTestCase assert_text @delegate.full_name end Percy.snapshot page, name: 'Delegates form on update' - fill_in 'admin_conferences_delegate_first_name', with: @delegate.first_name - fill_in 'admin_conferences_delegate_last_name', with: @delegate.last_name - select @delegate.institution.name, from: 'admin_conferences_delegate_institution_id' - fill_in 'admin_conferences_delegate_email_address', with: @delegate.email_address - fill_in 'admin_conferences_delegate_url', with: @delegate.url + fill_in 'delegate_first_name', with: @delegate.first_name + fill_in 'delegate_last_name', with: @delegate.last_name + select @delegate.institution.name, from: 'delegate_institution_id' + fill_in 'delegate_email_address', with: @delegate.email_address + fill_in 'delegate_url', with: @delegate.url @delegate - .conferences.each { |conference| select conference.name, from: 'admin_conferences_delegate_conference_ids' } + .conferences.each { |conference| select conference.name, from: 'delegate_conference_ids' } click_on 'Save delegate' assert_text 'Delegate saved' Percy.snapshot page, name: 'Delegates index on update' diff --git a/test/system/spina/admin/conferences/dietary_requirements_test.rb b/test/system/spina/admin/conferences/dietary_requirements_test.rb index 1dc9b094..904050ac 100644 --- a/test/system/spina/admin/conferences/dietary_requirements_test.rb +++ b/test/system/spina/admin/conferences/dietary_requirements_test.rb @@ -31,7 +31,7 @@ class DietaryRequirementsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text 'New dietary requirement' end - fill_in 'admin_conferences_dietary_requirement_name', with: @dietary_requirement.name + fill_in 'dietary_requirement_name', with: @dietary_requirement.name Percy.snapshot page, name: 'Dietary requirements form on create' click_on 'Save dietary requirement' assert_text 'Dietary requirement saved' @@ -47,7 +47,7 @@ class DietaryRequirementsTest < ApplicationSystemTestCase assert_text @dietary_requirement.name end Percy.snapshot page, name: 'Dietary requirements form on update' - fill_in 'admin_conferences_dietary_requirement_name', with: @dietary_requirement.name + fill_in 'dietary_requirement_name', with: @dietary_requirement.name click_on 'Save dietary requirement' assert_text 'Dietary requirement saved' Percy.snapshot page, name: 'Dietary requirements index on update' diff --git a/test/system/spina/admin/conferences/institutions_test.rb b/test/system/spina/admin/conferences/institutions_test.rb index 69fce07a..f257d539 100644 --- a/test/system/spina/admin/conferences/institutions_test.rb +++ b/test/system/spina/admin/conferences/institutions_test.rb @@ -32,8 +32,8 @@ class InstitutionsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text 'New institution' end - fill_in 'admin_conferences_institution_name', with: @institution.name - fill_in 'admin_conferences_institution_city', with: @institution.city + fill_in 'institution_name', with: @institution.name + fill_in 'institution_city', with: @institution.city execute_script '$.fx.off = true;' click_on 'Choose image' within '#overlay', visible: true, style: { display: 'block' } do @@ -56,8 +56,8 @@ class InstitutionsTest < ApplicationSystemTestCase assert_text @institution.name end Percy.snapshot page, name: 'Institutions form on update' - fill_in 'admin_conferences_institution_name', with: @institution.name - fill_in 'admin_conferences_institution_city', with: @institution.city + fill_in 'institution_name', with: @institution.name + fill_in 'institution_city', with: @institution.city page.execute_script '$.fx.off = true;' click_on 'Choose image' within '#overlay', visible: true, style: { display: 'block' } do diff --git a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb index 3db27799..fcee1323 100644 --- a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb +++ b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb @@ -31,7 +31,7 @@ class PresentationAttachmentTypesTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text 'New presentation attachment type' end - fill_in 'admin_conferences_presentation_attachment_type_name', with: @presentation_attachment_type.name + fill_in 'presentation_attachment_type_name', with: @presentation_attachment_type.name Percy.snapshot page, name: 'Presentation attachment types form on create' click_on 'Save presentation attachment type' assert_text 'Presentation attachment type saved' @@ -47,7 +47,7 @@ class PresentationAttachmentTypesTest < ApplicationSystemTestCase assert_text @presentation_attachment_type.name end Percy.snapshot page, name: 'Presentation attachment types form on update' - fill_in 'admin_conferences_presentation_attachment_type_name', with: @presentation_attachment_type.name + fill_in 'presentation_attachment_type_name', with: @presentation_attachment_type.name click_on 'Save presentation attachment type' assert_text 'Presentation attachment type saved' Percy.snapshot page, name: 'Presentation attachment types index on update' diff --git a/test/system/spina/admin/conferences/presentation_types_test.rb b/test/system/spina/admin/conferences/presentation_types_test.rb index e8cddb66..41350eb4 100644 --- a/test/system/spina/admin/conferences/presentation_types_test.rb +++ b/test/system/spina/admin/conferences/presentation_types_test.rb @@ -32,9 +32,9 @@ class PresentationTypesTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text 'New presentation type' end - select @presentation_type.conference.name, from: 'admin_conferences_presentation_type_conference_id' - fill_in 'admin_conferences_presentation_type_name', with: @presentation_type.name - fill_in 'admin_conferences_presentation_type_minutes', with: @presentation_type.minutes + select @presentation_type.conference.name, from: 'presentation_type_conference_id' + fill_in 'presentation_type_name', with: @presentation_type.name + fill_in 'presentation_type_minutes', with: @presentation_type.minutes Percy.snapshot page, name: 'Presentation types form on create' click_on 'Save presentation type' assert_text 'Presentation type saved' @@ -50,9 +50,9 @@ class PresentationTypesTest < ApplicationSystemTestCase assert_text @presentation_type.name end Percy.snapshot page, name: 'Presentation types form on update' - select @presentation_type.conference.name, from: 'admin_conferences_presentation_type_conference_id' - fill_in 'admin_conferences_presentation_type_name', with: @presentation_type.name - fill_in 'admin_conferences_presentation_type_minutes', with: @presentation_type.minutes + select @presentation_type.conference.name, from: 'presentation_type_conference_id' + fill_in 'presentation_type_name', with: @presentation_type.name + fill_in 'presentation_type_minutes', with: @presentation_type.minutes click_on 'Save presentation type' assert_text 'Presentation type saved' Percy.snapshot page, name: 'Presentation types index on update' diff --git a/test/system/spina/admin/conferences/presentations_test.rb b/test/system/spina/admin/conferences/presentations_test.rb index 9126cd48..a00d695d 100644 --- a/test/system/spina/admin/conferences/presentations_test.rb +++ b/test/system/spina/admin/conferences/presentations_test.rb @@ -31,20 +31,20 @@ class PresentationsTest < ApplicationSystemTestCase # rubocop:disable Metrics/Cl assert_selector '.breadcrumbs' do assert_text 'New presentation' end - select @presentation.conference.name, from: 'admin_conferences_conference_id' - select @presentation.presentation_type.name, from: 'admin_conferences_presentation_type_id' - select @presentation.session.name, from: 'admin_conferences_presentation_session_id' - fill_in 'admin_conferences_presentation_start_datetime', with: @presentation.start_datetime - fill_in 'admin_conferences_presentation_title', with: @presentation.title - fill_in_rich_text_area 'admin_conferences_presentation[abstract]', with: @presentation.abstract + select @presentation.conference.name, from: 'conference_id' + select @presentation.presentation_type.name, from: 'presentation_type_id' + select @presentation.session.name, from: 'presentation_session_id' + fill_in 'presentation_start_datetime', with: @presentation.start_datetime + fill_in 'presentation_title', with: @presentation.title + fill_in_rich_text_area 'presentation[abstract]', with: @presentation.abstract @presentation.presenters.each do |presenter| - select presenter.reversed_name_and_institution, from: 'admin_conferences_presentation_presenter_ids' + select presenter.reversed_name_and_institution, from: 'presentation_presenter_ids' end - within '.admin_conferences_presentation_attachment' do + within '.presentation_attachment' do click_link class: %w[button button-link icon] within '#structure_form_pane_0' do select @presentation.attachments.first.name, - from: 'admin_conferences_presentation_attachments_attributes_0_attachment_type_id' + from: 'presentation_attachments_attributes_0_attachment_type_id' click_on 'Choose from library' end end @@ -68,21 +68,21 @@ class PresentationsTest < ApplicationSystemTestCase # rubocop:disable Metrics/Cl assert_text @presentation.name end Percy.snapshot page, name: 'Presentations form on update' - select @presentation.conference.name, from: 'admin_conferences_conference_id' - select @presentation.presentation_type.name, from: 'admin_conferences_presentation_type_id' - select @presentation.session.name, from: 'admin_conferences_presentation_session_id' - fill_in 'admin_conferences_presentation_start_datetime', with: @presentation.start_datetime - fill_in 'admin_conferences_presentation_title', with: @presentation.title - fill_in_rich_text_area 'admin_conferences_presentation[abstract]', with: @presentation.abstract + select @presentation.conference.name, from: 'conference_id' + select @presentation.presentation_type.name, from: 'presentation_type_id' + select @presentation.session.name, from: 'presentation_session_id' + fill_in 'presentation_start_datetime', with: @presentation.start_datetime + fill_in 'presentation_title', with: @presentation.title + fill_in_rich_text_area 'presentation[abstract]', with: @presentation.abstract @presentation.presenters.each do |presenter| - select presenter.reversed_name_and_institution, from: 'admin_conferences_presentation_presenter_ids' + select presenter.reversed_name_and_institution, from: 'presentation_presenter_ids' end - within '.admin_conferences_presentation_attachment' do + within '.presentation_attachment' do click_link class: %w[button button-link icon] find_link(href: '#structure_form_pane_2').click within '#structure_form_pane_2' do select @presentation.attachments.second.name, - from: 'admin_conferences_presentation_attachments_attributes_2_attachment_type_id' + from: 'presentation_attachments_attributes_2_attachment_type_id' click_on 'Choose from library' end end diff --git a/test/system/spina/admin/conferences/rooms_test.rb b/test/system/spina/admin/conferences/rooms_test.rb index b7012a95..a56c8557 100644 --- a/test/system/spina/admin/conferences/rooms_test.rb +++ b/test/system/spina/admin/conferences/rooms_test.rb @@ -32,9 +32,9 @@ class RoomsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text 'New room' end - select @room.institution.name, from: 'admin_conferences_room_institution_id' - fill_in 'admin_conferences_room_building', with: @room.building - fill_in 'admin_conferences_room_number', with: @room.number + select @room.institution.name, from: 'room_institution_id' + fill_in 'room_building', with: @room.building + fill_in 'room_number', with: @room.number Percy.snapshot page, name: 'Rooms form on create' click_on 'Save room' assert_text 'Room saved' @@ -50,9 +50,9 @@ class RoomsTest < ApplicationSystemTestCase assert_text @room.name end Percy.snapshot page, name: 'Rooms form on update' - select @room.institution.name, from: 'admin_conferences_room_institution_id' - fill_in 'admin_conferences_room_building', with: @room.building - fill_in 'admin_conferences_room_number', with: @room.number + select @room.institution.name, from: 'room_institution_id' + fill_in 'room_building', with: @room.building + fill_in 'room_number', with: @room.number click_on 'Save room' assert_text 'Room saved' Percy.snapshot page, name: 'Rooms index on update' diff --git a/test/system/spina/admin/conferences/sessions_test.rb b/test/system/spina/admin/conferences/sessions_test.rb index 7e3b7b76..379d8a00 100644 --- a/test/system/spina/admin/conferences/sessions_test.rb +++ b/test/system/spina/admin/conferences/sessions_test.rb @@ -32,11 +32,11 @@ class SessionsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text 'New session' end - fill_in 'admin_conferences_session_name', with: @session.name - select @session.conference.name, from: 'admin_conferences_conference_id' - select @session.presentation_type.name, from: 'admin_conferences_session_presentation_type_id' - select @session.institution.name, from: 'admin_conferences_institution_id' - select @session.room.name, from: 'admin_conferences_session_room_id' + fill_in 'session_name', with: @session.name + select @session.conference.name, from: 'conference_id' + select @session.presentation_type.name, from: 'session_presentation_type_id' + select @session.institution.name, from: 'institution_id' + select @session.room.name, from: 'session_room_id' Percy.snapshot page, name: 'Sessions form on create' click_on 'Save session' assert_text 'Session saved' @@ -52,11 +52,11 @@ class SessionsTest < ApplicationSystemTestCase assert_text @session.name end Percy.snapshot page, name: 'Sessions form on update' - fill_in 'admin_conferences_session_name', with: @session.name - select @session.conference.name, from: 'admin_conferences_conference_id' - select @session.presentation_type.name, from: 'admin_conferences_session_presentation_type_id' - select @session.institution.name, from: 'admin_conferences_institution_id' - select @session.room.name, from: 'admin_conferences_session_room_id' + fill_in 'session_name', with: @session.name + select @session.conference.name, from: 'conference_id' + select @session.presentation_type.name, from: 'session_presentation_type_id' + select @session.institution.name, from: 'institution_id' + select @session.room.name, from: 'session_room_id' click_on 'Save session' assert_text 'Session saved' Percy.snapshot page, name: 'Sessions index on update' From 2dd1ad78308f291334bfe1873df2ed4525da1cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Tue, 23 Mar 2021 00:04:12 +0000 Subject: [PATCH 04/21] Clean up hooks --- .../admin/hooks/conferences/_primary_navigation.html.haml | 8 ++++---- .../conferences/_settings_secondary_navigation.html.haml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/spina/admin/hooks/conferences/_primary_navigation.html.haml b/app/views/spina/admin/hooks/conferences/_primary_navigation.html.haml index 499a6264..e04b0f30 100644 --- a/app/views/spina/admin/hooks/conferences/_primary_navigation.html.haml +++ b/app/views/spina/admin/hooks/conferences/_primary_navigation.html.haml @@ -7,13 +7,13 @@ %ul %li{ class: ('active' if %w[institutions rooms].include? controller_name) } - = link_to Spina::Admin::Conferences::Institution.model_name.human(count: 0), spina.admin_conferences_institutions_path + = link_to Spina::Admin::Conferences::Institution.model_name.human(count: 0), admin_conferences_institutions_path %li{ class: ('active' if %w[conferences presentation_types sessions].include? controller_name) } - = link_to Spina::Admin::Conferences::Conference.model_name.human(count: 0), spina.admin_conferences_conferences_path + = link_to Spina::Admin::Conferences::Conference.model_name.human(count: 0), admin_conferences_conferences_path %li{ class: ('active' if %w[delegates].include? controller_name) } - = link_to Spina::Admin::Conferences::Delegate.model_name.human(count: 0), spina.admin_conferences_delegates_path + = link_to Spina::Admin::Conferences::Delegate.model_name.human(count: 0), admin_conferences_delegates_path %li{ class: ('active' if %w[presentations].include? controller_name) } - = link_to Spina::Admin::Conferences::Presentation.model_name.human(count: 0), spina.admin_conferences_presentations_path + = link_to Spina::Admin::Conferences::Presentation.model_name.human(count: 0), admin_conferences_presentations_path %li = link_to '#', class: 'back-to-main-menu' do diff --git a/app/views/spina/admin/hooks/conferences/_settings_secondary_navigation.html.haml b/app/views/spina/admin/hooks/conferences/_settings_secondary_navigation.html.haml index b4de75fa..9a700c6e 100644 --- a/app/views/spina/admin/hooks/conferences/_settings_secondary_navigation.html.haml +++ b/app/views/spina/admin/hooks/conferences/_settings_secondary_navigation.html.haml @@ -1,6 +1,6 @@ %li{ class: ('active' if %w[dietary_requirements].include? controller_name) } - = link_to Spina::Admin::Conferences::DietaryRequirement.model_name.human(count: 0), spina.admin_conferences_dietary_requirements_path, + = link_to Spina::Admin::Conferences::DietaryRequirement.model_name.human(count: 0), admin_conferences_dietary_requirements_path, data: { turbolinks: 'false' } %li{ class: ('active' if %w[presentation_attachment_types].include? controller_name) } - = link_to Spina::Admin::Conferences::PresentationAttachmentType.model_name.human(count: 0), spina.admin_conferences_presentation_attachment_types_path, + = link_to Spina::Admin::Conferences::PresentationAttachmentType.model_name.human(count: 0), admin_conferences_presentation_attachment_types_path, data: { turbolinks: 'false' } From 63599e1018a23852749acb14b15f5e15eb5a8ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Thu, 25 Mar 2021 23:14:09 +0000 Subject: [PATCH 05/21] Introduce application-level collection partials --- .../application/_conferences.html.haml | 12 ++++++++ .../application/_delegates.html.haml | 11 ++++++++ .../_dietary_requirements.html.haml | 9 ++++++ .../application/_institutions.html.haml | 10 +++++++ .../_presentation_attachment_types.html.haml | 10 +++++++ .../application/_presentation_types.html.haml | 11 ++++++++ .../application/_presentations.html.haml | 11 ++++++++ .../conferences/application/_rooms.html.haml | 11 ++++++++ .../application/_sessions.html.haml | 11 ++++++++ .../conferences/_form_delegates.html.haml | 13 +-------- .../_form_presentation_types.html.haml | 13 +-------- .../conferences/_form_presentations.html.haml | 13 +-------- .../conferences/_form_rooms.html.haml | 13 +-------- .../conferences/conferences/index.html.haml | 14 +--------- .../delegates/_form_conferences.html.haml | 15 +--------- .../delegates/_form_presentations.html.haml | 13 +-------- .../conferences/delegates/index.html.haml | 13 +-------- .../_form_delegates.html.haml | 13 +-------- .../dietary_requirements/index.html.haml | 11 +------- .../institutions/_form_delegates.html.haml | 13 +-------- .../institutions/_form_rooms.html.haml | 13 +-------- .../conferences/institutions/index.html.haml | 12 +------- .../index.html.haml | 11 +------- .../_form_presentations.html.haml | 13 +-------- .../_form_sessions.html.haml | 13 +-------- .../presentation_types/index.html.haml | 13 +-------- .../presentations/_form_presenters.html.haml | 13 +-------- .../conferences/presentations/index.html.haml | 13 +-------- .../rooms/_form_presentations.html.haml | 13 +-------- .../admin/conferences/rooms/index.html.haml | 13 +-------- .../sessions/_form_presentations.html.haml | 13 +-------- .../conferences/sessions/index.html.haml | 13 +-------- config/locales/en.yml | 28 +++++++++++++------ .../conferences_controller_test.rb | 8 +++--- .../conferences/delegates_controller_test.rb | 4 +-- .../dietary_requirements_controller_test.rb | 2 +- .../institutions_controller_test.rb | 4 +-- .../presentation_types_controller_test.rb | 6 ++++ .../presentations_controller_test.rb | 2 +- .../conferences/rooms_controller_test.rb | 2 +- .../conferences/sessions_controller_test.rb | 2 +- 41 files changed, 156 insertions(+), 295 deletions(-) create mode 100644 app/views/spina/admin/conferences/application/_conferences.html.haml create mode 100644 app/views/spina/admin/conferences/application/_delegates.html.haml create mode 100644 app/views/spina/admin/conferences/application/_dietary_requirements.html.haml create mode 100644 app/views/spina/admin/conferences/application/_institutions.html.haml create mode 100644 app/views/spina/admin/conferences/application/_presentation_attachment_types.html.haml create mode 100644 app/views/spina/admin/conferences/application/_presentation_types.html.haml create mode 100644 app/views/spina/admin/conferences/application/_presentations.html.haml create mode 100644 app/views/spina/admin/conferences/application/_rooms.html.haml create mode 100644 app/views/spina/admin/conferences/application/_sessions.html.haml diff --git a/app/views/spina/admin/conferences/application/_conferences.html.haml b/app/views/spina/admin/conferences/application/_conferences.html.haml new file mode 100644 index 00000000..be56dcce --- /dev/null +++ b/app/views/spina/admin/conferences/application/_conferences.html.haml @@ -0,0 +1,12 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::Conference.human_attribute_name :name + %th= Spina::Admin::Conferences::Conference.human_attribute_name :year + %th= Spina::Admin::Conferences::Conference.human_attribute_name :start_date + %th= Spina::Admin::Conferences::Conference.human_attribute_name :finish_date + %th + + %tbody= render conferences.presence || 'empty_list', message: t('.no_conferences') diff --git a/app/views/spina/admin/conferences/application/_delegates.html.haml b/app/views/spina/admin/conferences/application/_delegates.html.haml new file mode 100644 index 00000000..872163fa --- /dev/null +++ b/app/views/spina/admin/conferences/application/_delegates.html.haml @@ -0,0 +1,11 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::Delegate.human_attribute_name :name + %th= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address + %th= Spina::Admin::Conferences::Delegate.human_attribute_name :institution + %th + + %tbody= render delegates.presence || 'empty_list', message: t('.no_delegates') diff --git a/app/views/spina/admin/conferences/application/_dietary_requirements.html.haml b/app/views/spina/admin/conferences/application/_dietary_requirements.html.haml new file mode 100644 index 00000000..fedbf0b9 --- /dev/null +++ b/app/views/spina/admin/conferences/application/_dietary_requirements.html.haml @@ -0,0 +1,9 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name + %th + + %tbody= render dietary_requirements.presence || 'empty_list', message: t('.no_dietary_requirements') diff --git a/app/views/spina/admin/conferences/application/_institutions.html.haml b/app/views/spina/admin/conferences/application/_institutions.html.haml new file mode 100644 index 00000000..0905af94 --- /dev/null +++ b/app/views/spina/admin/conferences/application/_institutions.html.haml @@ -0,0 +1,10 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::Institution.human_attribute_name :name + %th= Spina::Admin::Conferences::Institution.human_attribute_name :city + %th + + %tbody= render institutions.presence || 'empty_list', message: t('.no_institutions') diff --git a/app/views/spina/admin/conferences/application/_presentation_attachment_types.html.haml b/app/views/spina/admin/conferences/application/_presentation_attachment_types.html.haml new file mode 100644 index 00000000..1ca7cd8f --- /dev/null +++ b/app/views/spina/admin/conferences/application/_presentation_attachment_types.html.haml @@ -0,0 +1,10 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name + %th + + %tbody + = render presentation_attachment_types.presence || 'empty_list', message: t('.no_presentation_attachment_types') diff --git a/app/views/spina/admin/conferences/application/_presentation_types.html.haml b/app/views/spina/admin/conferences/application/_presentation_types.html.haml new file mode 100644 index 00000000..ee0d6e28 --- /dev/null +++ b/app/views/spina/admin/conferences/application/_presentation_types.html.haml @@ -0,0 +1,11 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :conference + %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :name + %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :duration + %th + + %tbody= render presentation_types.presence || 'empty_list', message: t('.no_presentation_types') diff --git a/app/views/spina/admin/conferences/application/_presentations.html.haml b/app/views/spina/admin/conferences/application/_presentations.html.haml new file mode 100644 index 00000000..764e1b0f --- /dev/null +++ b/app/views/spina/admin/conferences/application/_presentations.html.haml @@ -0,0 +1,11 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::Presentation.human_attribute_name :conference + %th= Spina::Admin::Conferences::Presentation.human_attribute_name :title + %th= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters + %th + + %tbody= render presentations.presence || 'empty_list', message: t('.no_presentations') diff --git a/app/views/spina/admin/conferences/application/_rooms.html.haml b/app/views/spina/admin/conferences/application/_rooms.html.haml new file mode 100644 index 00000000..126fa39c --- /dev/null +++ b/app/views/spina/admin/conferences/application/_rooms.html.haml @@ -0,0 +1,11 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::Room.human_attribute_name :institution + %th= Spina::Admin::Conferences::Room.human_attribute_name :building + %th= Spina::Admin::Conferences::Room.human_attribute_name :number + %th + + %tbody= render rooms.presence || 'empty_list', message: t('.no_rooms') diff --git a/app/views/spina/admin/conferences/application/_sessions.html.haml b/app/views/spina/admin/conferences/application/_sessions.html.haml new file mode 100644 index 00000000..39f748fb --- /dev/null +++ b/app/views/spina/admin/conferences/application/_sessions.html.haml @@ -0,0 +1,11 @@ +.well + .table-container + %table.table + %thead + %tr + %th= Spina::Admin::Conferences::Session.human_attribute_name :name + %th= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type + %th= Spina::Admin::Conferences::Session.human_attribute_name :room + %th + + %tbody= render sessions.presence || 'empty_list', message: t('.no_sessions') diff --git a/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml b/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml index 1306f4b2..f8c2fcbb 100644 --- a/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml @@ -1,12 +1 @@ -#delegates.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :name - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :institution - %th - - %tbody - = render @conference.delegates.any? ? @conference.delegates : 'empty_list', message: t('spina.admin.conferences.delegates.index.no_delegates') +#delegates.tab-content= render partial: 'delegates', object: @conference.delegates diff --git a/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml b/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml index 3b4f94f7..3afbf014 100644 --- a/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml @@ -1,12 +1 @@ -#presentation_types.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :conference - %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :name - %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :duration - %th - - %tbody - = render @conference.presentation_types.any? ? @conference.presentation_types : 'empty_list', message: t('spina.admin.conferences.presentation_types.index.no_presentation_types') +#presentation_types.tab-content= render partial: 'presentation_types', object: @conference.presentation_types diff --git a/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml b/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml index 77661546..184e6279 100644 --- a/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml @@ -1,12 +1 @@ -#presentations.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :title - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - %th - - %tbody - = render @conference.presentations.any? ? @conference.presentations : 'empty_list', message: t('spina.admin.conferences.presentations.index.no_presentations') +#presentations.tab-content= render partial: 'presentations', object: @conference.presentations diff --git a/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml b/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml index f09127ff..6f27fae0 100644 --- a/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml @@ -1,12 +1 @@ -#rooms.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Room.human_attribute_name :institution - %th= Spina::Admin::Conferences::Room.human_attribute_name :building - %th= Spina::Admin::Conferences::Room.human_attribute_name :number - %th - - %tbody - = render @conference.rooms.any? ? @conference.rooms : 'empty_list', message: t('spina.admin.conferences.rooms.index.no_rooms') +#rooms.tab-content= render partial: 'rooms', object: @conference.rooms diff --git a/app/views/spina/admin/conferences/conferences/index.html.haml b/app/views/spina/admin/conferences/conferences/index.html.haml index a8b1667e..9475d801 100644 --- a/app/views/spina/admin/conferences/conferences/index.html.haml +++ b/app/views/spina/admin/conferences/conferences/index.html.haml @@ -3,16 +3,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Conference.human_attribute_name :name - %th= Spina::Admin::Conferences::Conference.human_attribute_name :year - %th= Spina::Admin::Conferences::Conference.human_attribute_name :start_date - %th= Spina::Admin::Conferences::Conference.human_attribute_name :finish_date - %th - - %tbody - = render @conferences.any? ? @conferences : 'empty_list', message: t('.no_conferences') += render partial: 'conferences', object: @conferences diff --git a/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml b/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml index 98611e7c..67c5444a 100644 --- a/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml +++ b/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml @@ -1,14 +1 @@ -#conferences.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Conference.human_attribute_name :name - %th= Spina::Admin::Conferences::Conference.human_attribute_name :year - %th= Spina::Admin::Conferences::Conference.human_attribute_name :institution - %th= Spina::Admin::Conferences::Conference.human_attribute_name :start_date - %th= Spina::Admin::Conferences::Conference.human_attribute_name :finish_date - %th - - %tbody - = render @delegate.conferences.any? ? @delegate.conferences : 'empty_list', message: t('spina.admin.conferences.conferences.index.no_conferences') +#conferences.tab-content= render partial: 'conferences', object: @delegate.conferences diff --git a/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml b/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml index 981377d3..34958dba 100644 --- a/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml +++ b/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml @@ -1,12 +1 @@ -#presentations.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :title - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - %th - - %tbody - = render @delegate.presentations.any? ? @delegate.presentations : 'empty_list', message: t('spina.admin.conferences.presentations.index.no_presentations') +#presentations.tab-content= render partial: 'presentations', object: @delegate.presentations diff --git a/app/views/spina/admin/conferences/delegates/index.html.haml b/app/views/spina/admin/conferences/delegates/index.html.haml index 913a082a..17e92416 100644 --- a/app/views/spina/admin/conferences/delegates/index.html.haml +++ b/app/views/spina/admin/conferences/delegates/index.html.haml @@ -9,15 +9,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :name - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :institution - %th - - %tbody - = render @delegates.any? ? @delegates : 'empty_list', message: t('.no_delegates') += render partial: 'delegates', object: @delegates diff --git a/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml b/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml index 89fab612..a71bd7ec 100644 --- a/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml +++ b/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml @@ -1,12 +1 @@ -#delegates.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :name - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :institution - %th - - %tbody - = render @dietary_requirement.delegates.any? ? @dietary_requirement.delegates : 'empty_list', message: t('spina.admin.conferences.delegates.index.no_delegates') +#delegates.tab-content= render partial: 'delegates', object: @dietary_requirement.delegates diff --git a/app/views/spina/admin/conferences/dietary_requirements/index.html.haml b/app/views/spina/admin/conferences/dietary_requirements/index.html.haml index 1a285778..97d7844a 100644 --- a/app/views/spina/admin/conferences/dietary_requirements/index.html.haml +++ b/app/views/spina/admin/conferences/dietary_requirements/index.html.haml @@ -3,13 +3,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name - %th - - %tbody - = render @dietary_requirements.any? ? @dietary_requirements : 'empty_list', message: t('.no_dietary_requirements') += render partial: 'dietary_requirements', object: @dietary_requirements diff --git a/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml b/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml index ce29878f..6fdde5f4 100644 --- a/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml +++ b/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml @@ -1,12 +1 @@ -#delegates.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :name - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :institution - %th - - %tbody - = render @institution.delegates.any? ? @institution.delegates : 'empty_list', message: t('spina.admin.conferences.delegates.index.no_delegates') +#delegates.tab-content= render partial: 'delegates', object: @institution.delegates diff --git a/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml b/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml index f68262ff..a6acba69 100644 --- a/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml +++ b/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml @@ -1,12 +1 @@ -#rooms.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Room.human_attribute_name :institution - %th= Spina::Admin::Conferences::Room.human_attribute_name :building - %th= Spina::Admin::Conferences::Room.human_attribute_name :number - %th - - %tbody - = render @institution.rooms.any? ? @institution.rooms : 'empty_list', message: t('spina.admin.conferences.rooms.index.no_rooms') +#rooms.tab-content= render partial: 'rooms', object: @institution.rooms diff --git a/app/views/spina/admin/conferences/institutions/index.html.haml b/app/views/spina/admin/conferences/institutions/index.html.haml index 48964234..0e420bbd 100644 --- a/app/views/spina/admin/conferences/institutions/index.html.haml +++ b/app/views/spina/admin/conferences/institutions/index.html.haml @@ -3,14 +3,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Institution.human_attribute_name :name - %th= Spina::Admin::Conferences::Institution.human_attribute_name :city - %th - - %tbody - = render @institutions.any? ? @institutions : 'empty_list', message: t('.no_institutions') += render partial: 'institutions', object: @institutions diff --git a/app/views/spina/admin/conferences/presentation_attachment_types/index.html.haml b/app/views/spina/admin/conferences/presentation_attachment_types/index.html.haml index 73ff8d27..4eb30708 100644 --- a/app/views/spina/admin/conferences/presentation_attachment_types/index.html.haml +++ b/app/views/spina/admin/conferences/presentation_attachment_types/index.html.haml @@ -3,13 +3,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name - %th - - %tbody - = render @presentation_attachment_types.any? ? @presentation_attachment_types : 'empty_list', message: t('.no_presentation_attachment_types') += render partial: 'presentation_attachment_types', object: @presentation_attachment_types diff --git a/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml b/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml index a01ec816..719e73f5 100644 --- a/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml +++ b/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml @@ -1,12 +1 @@ -#presentations.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :title - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - %th - - %tbody - = render @presentation_type.presentations.any? ? @presentation_type.presentations : 'empty_list', message: t('spina.admin.conferences.presentations.index.no_presentations') +#presentations.tab-content= render partial: 'presentations', object: @presentation_type.presentations \ No newline at end of file diff --git a/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml b/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml index 8235c714..75ee621a 100644 --- a/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml +++ b/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml @@ -1,12 +1 @@ -#sessions.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Session.human_attribute_name :name - %th= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type - %th= Spina::Admin::Conferences::Session.human_attribute_name :room - %th - - %tbody - = render @presentation_type.sessions.any? ? @presentation_type.sessions : 'empty_list', message: t('spina.admin.conferences.sessions.index.no_sessions') +#sessions.tab-content= render partial: 'sessions', object: @presentation_type.sessions diff --git a/app/views/spina/admin/conferences/presentation_types/index.html.haml b/app/views/spina/admin/conferences/presentation_types/index.html.haml index dbebb100..15743c05 100644 --- a/app/views/spina/admin/conferences/presentation_types/index.html.haml +++ b/app/views/spina/admin/conferences/presentation_types/index.html.haml @@ -3,15 +3,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :conference - %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :name - %th= Spina::Admin::Conferences::PresentationType.human_attribute_name :duration - %th - - %tbody - = render @presentation_types.any? ? @presentation_types : 'empty_list', message: t('.no_presentation_types') += render partial: 'presentation_types', object: @presentation_types diff --git a/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml b/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml index 99be4829..02f54f32 100644 --- a/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml +++ b/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml @@ -1,12 +1 @@ -#presenters.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :name - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address - %th= Spina::Admin::Conferences::Delegate.human_attribute_name :institution - %th - - %tbody - = render @presentation.presenters.any? ? @presentation.presenters : 'empty_list', message: t('spina.admin.conferences.presenters.no_presenters') +#presenters.tab-content= render partial: 'delegates', object: @presentation.presenters diff --git a/app/views/spina/admin/conferences/presentations/index.html.haml b/app/views/spina/admin/conferences/presentations/index.html.haml index 53f44691..042f781a 100644 --- a/app/views/spina/admin/conferences/presentations/index.html.haml +++ b/app/views/spina/admin/conferences/presentations/index.html.haml @@ -9,15 +9,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :title - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - %th - - %tbody - = render @presentations.any? ? @presentations : 'empty_list', message: t('.no_presentations') += render partial: 'presentations', object: @presentations diff --git a/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml b/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml index f937e5ae..0f191d6e 100644 --- a/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml +++ b/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml @@ -1,12 +1 @@ -#presentations.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :title - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - %th - - %tbody - = render @room.presentations.any? ? @room.presentations : 'empty_list', message: t('spina.admin.conferences.presentations.index.no_presentations') +#presentations.tab-content= render partial: 'presentations', object: @room.presentations diff --git a/app/views/spina/admin/conferences/rooms/index.html.haml b/app/views/spina/admin/conferences/rooms/index.html.haml index d73e51fb..a632a252 100644 --- a/app/views/spina/admin/conferences/rooms/index.html.haml +++ b/app/views/spina/admin/conferences/rooms/index.html.haml @@ -3,15 +3,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Room.human_attribute_name :institution - %th= Spina::Admin::Conferences::Room.human_attribute_name :building - %th= Spina::Admin::Conferences::Room.human_attribute_name :number - %th - - %tbody - = render @rooms.any? ? @rooms : 'empty_list', message: t('.no_rooms') += render partial: 'rooms', object: @rooms diff --git a/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml b/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml index b449faa5..d8a6cef0 100644 --- a/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml +++ b/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml @@ -1,12 +1 @@ -#presentations.tab-content.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :title - %th= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - %th - - %tbody - = render @session.presentations.any? ? @session.presentations : 'empty_list', message: t('spina.admin.conferences.presentations.index.no_presentations') +#presentations.tab-content= render partial: 'presentations', object: @session.presentations diff --git a/app/views/spina/admin/conferences/sessions/index.html.haml b/app/views/spina/admin/conferences/sessions/index.html.haml index 64a9b2e8..5ea6e2d5 100644 --- a/app/views/spina/admin/conferences/sessions/index.html.haml +++ b/app/views/spina/admin/conferences/sessions/index.html.haml @@ -3,15 +3,4 @@ = icon 'plus' = t '.new' -.well - .table-container - %table.table - %thead - %tr - %th= Spina::Admin::Conferences::Session.human_attribute_name :name - %th= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type - %th= Spina::Admin::Conferences::Session.human_attribute_name :room - %th - - %tbody - = render @sessions.any? ? @sessions : 'empty_list', message: t('.no_sessions') += render partial: 'sessions', object: @sessions diff --git a/config/locales/en.yml b/config/locales/en.yml index e3514b28..49bde229 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -45,7 +45,6 @@ en: conferences: index: new: New conference - no_conferences: There are no conferences import: Import CSV new: new: New conference @@ -73,7 +72,6 @@ en: delegates: index: new: New delegate - no_delegates: There are no delegates import: Import CSV new: new: New delegate @@ -108,7 +106,6 @@ en: presentations: index: new: New presentation - no_presentations: There are no presentations import: Import CSV new: new: New presentation @@ -131,7 +128,6 @@ en: presentation_types: index: new: New presentation type - no_presentation_types: There are no presentation types import: Import CSV new: new: New presentation type @@ -154,7 +150,6 @@ en: dietary_requirements: index: new: New dietary requirement - no_dietary_requirements: There are no dietary requirements import: Import CSV new: new: New dietary requirement @@ -175,7 +170,6 @@ en: presentation_attachment_types: index: new: New presentation attachment type - no_presentation_attachment_types: There are no presentation attachment types new: new: New presentation attachment type create: @@ -193,7 +187,6 @@ en: institutions: index: new: New institution - no_institutions: There are no institutions import: Import CSV new: new: New institution @@ -215,7 +208,6 @@ en: rooms: index: new: New room - no_rooms: There are no rooms import: Import CSV new: new: New room @@ -235,7 +227,6 @@ en: sessions: index: new: New session - no_sessions: There are no sessions new: new: New session create: @@ -251,6 +242,25 @@ en: presentations: Presentations form_session_details: delete_confirmation: "Are you sure you want to delete the session %{session}?" + application: + conferences: + no_conferences: There are no conferences + delegates: + no_delegates: There are no delegates + dietary_requirements: + no_dietary_requirements: There are no dietary requirements + institutions: + no_institutions: There are no institutions + presentation_types: + no_presentation_types: There are no presentation types + presentations: + no_presentations: There are no presentations + presentation_attachment_types: + no_presentation_attachment_types: There are no presentation attachment types + rooms: + no_rooms: There are no rooms + sessions: + no_sessions: There are no sessions activerecord: models: spina/admin/conferences/conference: diff --git a/test/controllers/spina/admin/conferences/conferences_controller_test.rb b/test/controllers/spina/admin/conferences/conferences_controller_test.rb index c852b690..4c8bd735 100644 --- a/test/controllers/spina/admin/conferences/conferences_controller_test.rb +++ b/test/controllers/spina/admin/conferences/conferences_controller_test.rb @@ -27,16 +27,16 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa get new_admin_conferences_conference_url assert_response :success assert_select '#delegates tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.delegates.index.no_delegates') + assert_select 'td', 'There are no delegates' end assert_select '#presentation_types tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.presentation_types.index.no_presentation_types') + assert_select 'td', 'There are no presentation types' end assert_select '#presentations tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.presentations.index.no_presentations') + assert_select 'td', 'There are no presentations' end assert_select '#rooms tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.rooms.index.no_rooms') + assert_select 'td', 'There are no rooms' end end diff --git a/test/controllers/spina/admin/conferences/delegates_controller_test.rb b/test/controllers/spina/admin/conferences/delegates_controller_test.rb index 9894c76d..8649f39f 100644 --- a/test/controllers/spina/admin/conferences/delegates_controller_test.rb +++ b/test/controllers/spina/admin/conferences/delegates_controller_test.rb @@ -24,10 +24,10 @@ class DelegatesControllerTest < ActionDispatch::IntegrationTest # rubocop:disabl get new_admin_conferences_delegate_url assert_response :success assert_select '#conferences tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.conferences.index.no_conferences') + assert_select 'td', 'There are no conferences' end assert_select '#presentations tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.presentations.index.no_presentations') + assert_select 'td', 'There are no presentations' end end diff --git a/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb b/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb index c89a3811..ad77e506 100644 --- a/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb +++ b/test/controllers/spina/admin/conferences/dietary_requirements_controller_test.rb @@ -25,7 +25,7 @@ class DietaryRequirementsControllerTest < ActionDispatch::IntegrationTest # rubo get new_admin_conferences_dietary_requirement_url assert_response :success assert_select '#delegates tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.delegates.index.no_delegates') + assert_select 'td', 'There are no delegates' end end diff --git a/test/controllers/spina/admin/conferences/institutions_controller_test.rb b/test/controllers/spina/admin/conferences/institutions_controller_test.rb index f484970b..18817a76 100644 --- a/test/controllers/spina/admin/conferences/institutions_controller_test.rb +++ b/test/controllers/spina/admin/conferences/institutions_controller_test.rb @@ -25,10 +25,10 @@ class InstitutionsControllerTest < ActionDispatch::IntegrationTest # rubocop:dis get new_admin_conferences_institution_url assert_response :success assert_select '#delegates tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.delegates.index.no_delegates') + assert_select 'td', 'There are no delegates' end assert_select '#rooms tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.rooms.index.no_rooms') + assert_select 'td', 'There are no rooms' end end diff --git a/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb b/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb index 76af65be..13919119 100644 --- a/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb +++ b/test/controllers/spina/admin/conferences/presentation_types_controller_test.rb @@ -25,6 +25,12 @@ class PresentationTypesControllerTest < ActionDispatch::IntegrationTest # ruboco test 'should get new' do get new_admin_conferences_presentation_type_url assert_response :success + assert_select '#presentations tbody > tr' do + assert_select 'td', 'There are no presentations' + end + assert_select '#sessions tbody > tr' do + assert_select 'td', 'There are no sessions' + end end test 'should get edit' do diff --git a/test/controllers/spina/admin/conferences/presentations_controller_test.rb b/test/controllers/spina/admin/conferences/presentations_controller_test.rb index 8287ed75..b3a7abd6 100644 --- a/test/controllers/spina/admin/conferences/presentations_controller_test.rb +++ b/test/controllers/spina/admin/conferences/presentations_controller_test.rb @@ -24,7 +24,7 @@ class PresentationsControllerTest < ActionDispatch::IntegrationTest # rubocop:di get new_admin_conferences_presentation_url assert_response :success assert_select '#presenters tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.presenters.no_presenters') + assert_select 'td', 'There are no delegates' end end diff --git a/test/controllers/spina/admin/conferences/rooms_controller_test.rb b/test/controllers/spina/admin/conferences/rooms_controller_test.rb index f940eb31..e8771582 100644 --- a/test/controllers/spina/admin/conferences/rooms_controller_test.rb +++ b/test/controllers/spina/admin/conferences/rooms_controller_test.rb @@ -25,7 +25,7 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable Me get new_admin_conferences_room_url assert_response :success assert_select '#presentations tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.presentations.index.no_presentations') + assert_select 'td', 'There are no presentations' end end diff --git a/test/controllers/spina/admin/conferences/sessions_controller_test.rb b/test/controllers/spina/admin/conferences/sessions_controller_test.rb index 702b6bef..50663593 100644 --- a/test/controllers/spina/admin/conferences/sessions_controller_test.rb +++ b/test/controllers/spina/admin/conferences/sessions_controller_test.rb @@ -25,7 +25,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest # rubocop:disable get new_admin_conferences_session_url assert_response :success assert_select '#presentations tbody > tr' do - assert_select 'td', I18n.t('spina.admin.conferences.presentations.index.no_presentations') + assert_select 'td', 'There are no presentations' end end From 9f4a08f14f6b74ffd6639a75dc466590ceca2713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Tue, 23 Mar 2021 00:04:45 +0000 Subject: [PATCH 06/21] Add missing link to session partial --- app/views/spina/admin/conferences/sessions/_session.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spina/admin/conferences/sessions/_session.html.haml b/app/views/spina/admin/conferences/sessions/_session.html.haml index 6f31be6d..c8dcb7d7 100644 --- a/app/views/spina/admin/conferences/sessions/_session.html.haml +++ b/app/views/spina/admin/conferences/sessions/_session.html.haml @@ -1,5 +1,5 @@ %tr{ data: { session_id: session.id } } - %td= session.name + %td= link_to session.name, edit_admin_conferences_session_path(session) %td= session.presentation_type_name %td= session.room_name %td.align-right From 870ae254d189426afa74782144f8b70a92aa8dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Sun, 4 Apr 2021 02:04:32 +0100 Subject: [PATCH 07/21] Add missing translation --- config/locales/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 49bde229..a5c0d334 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -299,6 +299,7 @@ en: attributes: spina/admin/conferences/conference: name: Name + year: Year start_datetime: Start time finish_datetime: Finish time events: Events From efbad23ad8222768fdf6cdcde2480fc2a2c6d198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Fri, 26 Mar 2021 00:25:02 +0000 Subject: [PATCH 08/21] Remove calendar picker CSS --- .../stylesheets/spina/admin/conferences/application.sass | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/assets/stylesheets/spina/admin/conferences/application.sass b/app/assets/stylesheets/spina/admin/conferences/application.sass index 923ef3aa..073fa524 100644 --- a/app/assets/stylesheets/spina/admin/conferences/application.sass +++ b/app/assets/stylesheets/spina/admin/conferences/application.sass @@ -1,10 +1,3 @@ -input::-webkit-calendar-picker-indicator - display: none -input[type="date"]::-webkit-outer-spin-button, input[type="date"]::-webkit-inner-spin-button, input[type="time"]::-webkit-inner-spin-button, input[type="time"]::-webkit-inner-spin-button - display: none -input[type="date"] - padding-right: 30px - .multiple.select-dropdown z-index: 0 &:before From c4ef9e110403883073001840fcbde4fde2aae288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Mon, 22 Mar 2021 23:57:22 +0000 Subject: [PATCH 09/21] Set locale before all actions --- .../spina/admin/conferences/application_controller.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/controllers/spina/admin/conferences/application_controller.rb b/app/controllers/spina/admin/conferences/application_controller.rb index 6dc2de13..f4e3cc9b 100644 --- a/app/controllers/spina/admin/conferences/application_controller.rb +++ b/app/controllers/spina/admin/conferences/application_controller.rb @@ -10,6 +10,13 @@ class ApplicationController < ::Spina::Admin::AdminController add_flash_types :success layout 'spina/admin/conferences/application', only: %i[new edit] + before_action :set_locale + + private + + def set_locale + @locale = params[:locale] || I18n.default_locale + end end end end From e1f0008bc336aa67bf50a460e8968bc7053804f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 10:30:38 +0000 Subject: [PATCH 10/21] Update spina requirement from ~> 1.1 to >= 1.1, < 3.0 Updates the requirements on [spina](https://github.com/SpinaCMS/Spina) to permit the latest version. - [Release notes](https://github.com/SpinaCMS/Spina/releases) - [Changelog](https://github.com/SpinaCMS/Spina/blob/master/CHANGELOG.md) - [Commits](https://github.com/SpinaCMS/Spina/compare/v1.2.0...v2.0.0) Signed-off-by: dependabot[bot] Avoid widened dependency Update spina requirement from ~> 1.1 to >= 1.1, < 3.0 Updates the requirements on [spina](https://github.com/SpinaCMS/Spina) to permit the latest version. - [Release notes](https://github.com/SpinaCMS/Spina/releases) - [Changelog](https://github.com/SpinaCMS/Spina/blob/master/CHANGELOG.md) - [Commits](https://github.com/SpinaCMS/Spina/compare/v1.2.0...v2.0.2) Signed-off-by: dependabot[bot] --- Gemfile.lock | 17 ++++++++++------- spina-admin-conferences.gemspec | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 39449f72..840405ff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ PATH rails (~> 6.0) rails-i18n (~> 6.0) redis (~> 4.2) - spina (~> 1.1) + spina (~> 2.0) stimulus-rails (~> 0.2.2) turbo-rails (~> 0.5.9) @@ -78,6 +78,8 @@ GEM activerecord (>= 4.2.0) ansi (1.5.0) ast (2.4.2) + attr_json (1.3.0) + activerecord (>= 5.0.0, < 6.2) bcrypt (3.1.16) bindex (0.8.1) breadcrumbs_on_rails (4.0.0) @@ -110,7 +112,7 @@ GEM erubi (1.10.0) erubis (2.7.0) execjs (2.7.0) - ffi (1.14.2) + ffi (1.15.0) globalid (0.4.2) activesupport (>= 4.2.0) haml (5.2.1) @@ -127,7 +129,7 @@ GEM haml (>= 4.0, < 6) nokogiri (>= 1.6.0) ruby_parser (~> 3.5) - i18n (1.8.9) + i18n (1.8.10) concurrent-ruby (~> 1.0) icalendar (2.7.1) ice_cube (~> 0.16) @@ -286,20 +288,21 @@ GEM simplecov-html (0.12.3) simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.2) - spina (1.2.0) + spina (2.0.2) ancestry + attr_json bcrypt breadcrumbs_on_rails coffee-rails haml-rails + image_processing jquery-rails jsonb_accessor (>= 1.0.0) kaminari - mini_magick - mobility (>= 0.8.9) + mobility (= 1.1.1) pg rack-rewrite (>= 1.5.0) - rails (>= 5.2) + rails (>= 6.0) sass-rails turbolinks (~> 5) sprockets (4.0.2) diff --git a/spina-admin-conferences.gemspec b/spina-admin-conferences.gemspec index 0bb6658b..15d0041e 100644 --- a/spina-admin-conferences.gemspec +++ b/spina-admin-conferences.gemspec @@ -27,7 +27,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength spec.add_dependency 'rails', '~> 6.0' spec.add_dependency 'rails-i18n', '~> 6.0' spec.add_dependency 'redis', '~> 4.2' - spec.add_dependency 'spina', '~> 1.1' + spec.add_dependency 'spina', '~> 2.0' spec.add_dependency 'stimulus-rails', '~> 0.2.2' spec.add_dependency 'turbo-rails', '~> 0.5.9' From a2d1521d0ead772d6d341501c9dce3c71d4713a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Wed, 24 Mar 2021 00:36:05 +0000 Subject: [PATCH 11/21] Update schema for new parts and slug Update schema for new parts and slug, switch to new parts, add missing translation, update forms for new parts --- .../conferences/conferences_controller.rb | 41 +- .../admin/conferences/conferences_helper.rb | 44 -- .../spina/admin/conferences/conference.rb | 11 +- .../spina/admin/conferences/date_part.rb | 15 - .../admin/conferences/email_address_part.rb | 21 - app/models/spina/admin/conferences/part.rb | 20 - .../spina/admin/conferences/presentation.rb | 5 + .../spina/admin/conferences/time_part.rb | 15 - .../spina/admin/conferences/url_part.rb | 21 - .../spina/parts/admin/conferences/date.rb | 14 + .../parts/admin/conferences/email_address.rb | 20 + .../spina/parts/admin/conferences/time.rb | 14 + .../spina/parts/admin/conferences/url.rb | 20 + .../conferences/_form_parts.html.haml | 11 +- .../_form_institution_details.html.haml | 32 +- .../_attachment_fields.html.haml | 15 +- .../conferences/date_parts/_form.html.haml | 5 - .../email_address_parts/_form.html.haml | 5 - .../conferences/time_parts/_form.html.haml | 5 - .../conferences/url_parts/_form.html.haml | 5 - .../admin/conferences/dates/_form.html.haml | 2 + .../email_addresses/_form.html.haml | 2 + .../admin/conferences/times/_form.html.haml | 2 + .../admin/conferences/urls/_form.html.haml | 2 + config/locales/en.yml | 1 + ...utes_to_spina_conferences_presentations.rb | 7 + ...ibutes_to_spina_conferences_conferences.rb | 7 + ...0210315164411_convert_partables_to_json.rb | 415 ++++++++++++++++++ lib/spina/admin/conferences/engine.rb | 5 + test/application_system_test_case.rb | 2 + .../conferences_controller_test.rb | 97 ++-- .../config/initializers/themes/default.rb | 187 ++++---- ...json_attributes_to_spina_accounts.spina.rb | 6 + ...dd_json_attributes_to_spina_pages.spina.rb | 6 + ...01208_add_slug_to_spina_resources.spina.rb | 6 + test/dummy/db/schema.rb | 7 +- test/fixtures/active_storage/attachments.yml | 46 ++ test/fixtures/active_storage/blobs.yml | 15 + test/fixtures/files/constitution.pdf | Bin test/fixtures/files/logo.png | Bin 0 -> 87009 bytes test/fixtures/files/minutes.pdf | Bin test/fixtures/files/profile_picture.jpg | Bin 0 -> 143124 bytes .../spina/admin/conferences/conferences.yml | 90 ++++ .../spina/admin/conferences/date_parts.yml | 8 - .../admin/conferences/email_address_parts.yml | 8 - .../spina/admin/conferences/institutions.yml | 6 +- .../spina/admin/conferences/parts.yml | 101 ----- .../spina/admin/conferences/time_parts.yml | 8 - .../spina/admin/conferences/url_parts.yml | 8 - test/fixtures/spina/attachments.yml | 4 + test/fixtures/spina/image_collections.yml | 7 - .../spina/image_collections_images.yml | 15 - test/fixtures/spina/images.yml | 4 + test/fixtures/spina/layout_parts.yml | 25 -- test/fixtures/spina/line/translations.yml | 10 - test/fixtures/spina/lines.yml | 7 - test/fixtures/spina/page_parts.yml | 86 ---- test/fixtures/spina/pages.yml | 149 +++++++ test/fixtures/spina/structure_items.yml | 17 - test/fixtures/spina/structure_parts.yml | 91 ---- test/fixtures/spina/structures.yml | 13 - test/fixtures/spina/text/translations.yml | 27 -- test/fixtures/spina/texts.yml | 7 - .../conferences/conferences_helper_test.rb | 61 --- .../admin/conferences/conference_test.rb | 32 -- .../spina/admin/conferences/date_part_test.rb | 36 -- .../conferences/email_address_part_test.rb | 44 -- .../spina/admin/conferences/part_test.rb | 65 --- .../spina/admin/conferences/time_part_test.rb | 36 -- .../spina/admin/conferences/url_part_test.rb | 48 -- .../parts/admin/conferences/date_test.rb | 23 + .../admin/conferences/email_address_test.rb | 31 ++ .../parts/admin/conferences/time_test.rb | 23 + .../spina/parts/admin/conferences/url_test.rb | 34 ++ .../admin/conferences/conferences_test.rb | 100 ++--- .../spina/admin/conferences/delegates_test.rb | 10 +- .../conferences/dietary_requirements_test.rb | 10 +- .../admin/conferences/institutions_test.rb | 26 +- .../presentation_attachment_types_test.rb | 10 +- .../conferences/presentation_types_test.rb | 10 +- .../admin/conferences/presentations_test.rb | 34 +- .../spina/admin/conferences/rooms_test.rb | 10 +- .../spina/admin/conferences/sessions_test.rb | 10 +- test/test_helper.rb | 26 ++ 84 files changed, 1238 insertions(+), 1286 deletions(-) delete mode 100644 app/helpers/spina/admin/conferences/conferences_helper.rb delete mode 100644 app/models/spina/admin/conferences/date_part.rb delete mode 100644 app/models/spina/admin/conferences/email_address_part.rb delete mode 100644 app/models/spina/admin/conferences/part.rb delete mode 100644 app/models/spina/admin/conferences/time_part.rb delete mode 100644 app/models/spina/admin/conferences/url_part.rb create mode 100644 app/models/spina/parts/admin/conferences/date.rb create mode 100644 app/models/spina/parts/admin/conferences/email_address.rb create mode 100644 app/models/spina/parts/admin/conferences/time.rb create mode 100644 app/models/spina/parts/admin/conferences/url.rb delete mode 100644 app/views/spina/admin/partables/admin/conferences/date_parts/_form.html.haml delete mode 100644 app/views/spina/admin/partables/admin/conferences/email_address_parts/_form.html.haml delete mode 100644 app/views/spina/admin/partables/admin/conferences/time_parts/_form.html.haml delete mode 100644 app/views/spina/admin/partables/admin/conferences/url_parts/_form.html.haml create mode 100644 app/views/spina/admin/parts/admin/conferences/dates/_form.html.haml create mode 100644 app/views/spina/admin/parts/admin/conferences/email_addresses/_form.html.haml create mode 100644 app/views/spina/admin/parts/admin/conferences/times/_form.html.haml create mode 100644 app/views/spina/admin/parts/admin/conferences/urls/_form.html.haml create mode 100644 db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb create mode 100644 db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb create mode 100644 db/migrate/20210315164411_convert_partables_to_json.rb create mode 100644 test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb create mode 100644 test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb create mode 100644 test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb create mode 100644 test/fixtures/active_storage/attachments.yml create mode 100644 test/fixtures/active_storage/blobs.yml create mode 100644 test/fixtures/files/constitution.pdf create mode 100644 test/fixtures/files/logo.png create mode 100644 test/fixtures/files/minutes.pdf create mode 100644 test/fixtures/files/profile_picture.jpg delete mode 100644 test/fixtures/spina/admin/conferences/date_parts.yml delete mode 100644 test/fixtures/spina/admin/conferences/email_address_parts.yml delete mode 100644 test/fixtures/spina/admin/conferences/parts.yml delete mode 100644 test/fixtures/spina/admin/conferences/time_parts.yml delete mode 100644 test/fixtures/spina/admin/conferences/url_parts.yml delete mode 100644 test/fixtures/spina/image_collections.yml delete mode 100644 test/fixtures/spina/image_collections_images.yml delete mode 100644 test/fixtures/spina/layout_parts.yml delete mode 100644 test/fixtures/spina/line/translations.yml delete mode 100644 test/fixtures/spina/lines.yml delete mode 100644 test/fixtures/spina/page_parts.yml delete mode 100644 test/fixtures/spina/structure_items.yml delete mode 100644 test/fixtures/spina/structure_parts.yml delete mode 100644 test/fixtures/spina/structures.yml delete mode 100644 test/fixtures/spina/text/translations.yml delete mode 100644 test/fixtures/spina/texts.yml delete mode 100644 test/helpers/spina/admin/conferences/conferences_helper_test.rb delete mode 100644 test/models/spina/admin/conferences/date_part_test.rb delete mode 100644 test/models/spina/admin/conferences/email_address_part_test.rb delete mode 100644 test/models/spina/admin/conferences/part_test.rb delete mode 100644 test/models/spina/admin/conferences/time_part_test.rb delete mode 100644 test/models/spina/admin/conferences/url_part_test.rb create mode 100644 test/models/spina/parts/admin/conferences/date_test.rb create mode 100644 test/models/spina/parts/admin/conferences/email_address_test.rb create mode 100644 test/models/spina/parts/admin/conferences/time_test.rb create mode 100644 test/models/spina/parts/admin/conferences/url_test.rb diff --git a/app/controllers/spina/admin/conferences/conferences_controller.rb b/app/controllers/spina/admin/conferences/conferences_controller.rb index 443cdad3..39404d56 100644 --- a/app/controllers/spina/admin/conferences/conferences_controller.rb +++ b/app/controllers/spina/admin/conferences/conferences_controller.rb @@ -6,16 +6,21 @@ module Conferences # Controller for {Conference} objects. # @see Conference class ConferencesController < ApplicationController - PARTS = [ - { name: 'text', title: 'Text', partable_type: 'Spina::Text' }, - { name: 'submission_url', title: 'Submission URL', partable_type: 'Spina::Admin::Conferences::UrlPart' }, - { name: 'submission_email_address', title: 'Submission email address', - partable_type: 'Spina::Admin::Conferences::EmailAddressPart' }, - { name: 'submission_date', title: 'Submission date', partable_type: 'Spina::Admin::Conferences::DatePart' }, - { name: 'submission_text', title: 'Submission text', partable_type: 'Spina::Line' }, - { name: 'gallery', title: 'Gallery', partable_type: 'Spina::ImageCollection' }, - { name: 'sponsors', title: 'Sponsors', partable_type: 'Spina::Structure' } + PARTS_PARAMS = [ + :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, + images_attributes: %i[filename signed_blob_id image_id alt], + content_attributes: [ + :name, :title, + parts_attributes: [ + :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, + images_attributes: %i[filename signed_blob_id image_id alt] + ] + ] ].freeze + CONTENT_PARAMS = Spina.config.locales.inject({}) { |params, locale| params.merge("#{locale}_content_attributes": [*PARTS_PARAMS]) } + PARAMS = [:start_date, :finish_date, :name, **CONTENT_PARAMS, + events_attributes: %i[id name start_datetime finish_datetime description location]].freeze + PARTS = %w[text submission_url submission_email_address submission_date submission_text gallery sponsors].freeze before_action :set_conference, only: %i[edit update destroy] before_action :set_conferences_breadcrumb @@ -116,29 +121,17 @@ def set_tabs end def set_parts_attributes - @parts_attributes = PARTS + @parts_attributes = current_theme.parts.select { |part| PARTS.include? part[:name] } end def build_parts return unless @parts_attributes.is_a? Array - @conference.parts = @parts_attributes.collect do |part_attributes| - @conference.parts.where(name: part_attributes[:name]).first_or_initialize(**part_attributes) - .tap { |part| part.partable ||= part.partable_type.constantize.new } - end + @parts = @parts_attributes.collect { |part_attributes| @conference.part(part_attributes) } end def conference_params - params.require(:conference).permit(:start_date, :finish_date, :name, - events_attributes: %i[id name start_datetime finish_datetime description location], - parts_attributes: [:id, :title, :name, :partable_type, :partable_id, - { partable_attributes: - [:id, :content, :image_tokens, :image_positions, :date, :time, - { structure_items_attributes: - [:id, :position, :_destroy, - { structure_parts_attributes: - [:id, :title, :structure_partable_type, :name, :partable_id, - { partable_attributes: {} }] }] }] }]) + params.require(:conference).permit(PARAMS) end end end diff --git a/app/helpers/spina/admin/conferences/conferences_helper.rb b/app/helpers/spina/admin/conferences/conferences_helper.rb deleted file mode 100644 index 2b291c3d..00000000 --- a/app/helpers/spina/admin/conferences/conferences_helper.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -module Spina - module Admin - module Conferences - # Helper for conferences - module ConferencesHelper - STRUCTURES = [ - { name: 'sponsors', structure_parts: [ - { name: 'name', title: 'Name', partable_type: 'Spina::Line' }, - { name: 'logo', title: 'Logo', partable_type: 'Spina::Image' }, - { name: 'website', title: 'Website', partable_type: 'Spina::Admin::Conferences::UrlPart' } - ] } - ].freeze - - def new_custom_structure_item(form, part) - item = StructureItem.new - build_custom_structure_parts(part.name, item) - fields = form.fields_for(:structure_items, item, child_index: item.object_id) do |builder| - render('spina/admin/conferences/conferences/form_structure_item', f: builder, structure: part) - end - link_to icon('plus'), '#', class: %w[add_structure_item_fields button button-link], - data: { id: item.object_id, fields: fields.squish } - end - - def build_custom_structure_parts(name, item) - structure = STRUCTURES.find { |structure_attributes| structure_attributes[:name] == name } - return item.parts if structure.blank? - - structure[:structure_parts].map { |part_attributes| build_custom_structure_part(item.parts, part_attributes) } - end - - private - - def build_custom_structure_part(parts, part_attributes) - parts.where(name: part_attributes[:name]).first_or_initialize(**part_attributes).then do |part| - part.partable ||= part.partable_type.constantize.new - part - end - end - end - end - end -end diff --git a/app/models/spina/admin/conferences/conference.rb b/app/models/spina/admin/conferences/conference.rb index 38856980..6b907f98 100644 --- a/app/models/spina/admin/conferences/conference.rb +++ b/app/models/spina/admin/conferences/conference.rb @@ -13,7 +13,10 @@ module Conferences # = Translations # - {#name} class Conference < ApplicationRecord - include Partable + include AttrJson::Record + include AttrJson::NestedAttributes + include Spina::Partable + include Spina::TranslatedContent default_scope { includes(:translations) } @@ -37,11 +40,6 @@ class Conference < ApplicationRecord # @note Destroying a conference destroys dependent events. # @see Event has_many :events, -> { includes(:translations) }, inverse_of: :conference, dependent: :destroy - # @!attribute [rw] events - # @return [ActiveRecord::Relation] directly associated events - # @note Destroying a conference destroys dependent events. - # @see Event - has_many :parts, as: :pageable, dependent: :destroy # @!attribute [rw] sessions # @return [ActiveRecord::Relation] Sessions associated with {#presentation_types} # @see Session @@ -68,7 +66,6 @@ class Conference < ApplicationRecord has_and_belongs_to_many :delegates, foreign_key: :spina_conferences_conference_id, # rubocop:disable Rails/HasAndBelongsToMany association_foreign_key: :spina_conferences_delegate_id accepts_nested_attributes_for :events, allow_destroy: true - accepts_nested_attributes_for :parts, allow_destroy: true validates :name, :start_date, :finish_date, :year, presence: true validates :finish_date, 'spina/admin/conferences/finish_date': true, unless: proc { |conference| conference.start_date.blank? } diff --git a/app/models/spina/admin/conferences/date_part.rb b/app/models/spina/admin/conferences/date_part.rb deleted file mode 100644 index d2a52f8a..00000000 --- a/app/models/spina/admin/conferences/date_part.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module Spina - module Admin - module Conferences - # Date parts, without associated times. - class DatePart < ApplicationRecord - has_many :page_parts, as: :page_partable - has_many :parts, as: :partable - has_many :layout_parts, as: :layout_partable - has_many :structure_parts, as: :structure_partable - end - end - end -end diff --git a/app/models/spina/admin/conferences/email_address_part.rb b/app/models/spina/admin/conferences/email_address_part.rb deleted file mode 100644 index 1e9c4395..00000000 --- a/app/models/spina/admin/conferences/email_address_part.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module Spina - module Admin - module Conferences - # Email address parts. The format is validated. - # - # = Validators - # Email address (using {EmailAddressValidator}):: {#content}. - # @see EmailAddressValidator - class EmailAddressPart < ApplicationRecord - has_many :page_parts, as: :page_partable - has_many :parts, as: :partable - has_many :layout_parts, as: :layout_partable - has_many :structure_parts, as: :structure_partable - - validates :content, 'spina/admin/conferences/email_address': true, allow_blank: true - end - end - end -end diff --git a/app/models/spina/admin/conferences/part.rb b/app/models/spina/admin/conferences/part.rb deleted file mode 100644 index ebd0de8c..00000000 --- a/app/models/spina/admin/conferences/part.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -module Spina - module Admin - module Conferences - # Join records between partables and pageables. - class Part < ApplicationRecord - include Spina::Part - include Spina::Optionable - - belongs_to :pageable, inverse_of: :parts, polymorphic: true, touch: true - belongs_to :partable, polymorphic: true, optional: true - - accepts_nested_attributes_for :partable - - validates :name, uniqueness: { scope: :pageable_id } - end - end - end -end diff --git a/app/models/spina/admin/conferences/presentation.rb b/app/models/spina/admin/conferences/presentation.rb index 4b1f0b0d..89b043c2 100644 --- a/app/models/spina/admin/conferences/presentation.rb +++ b/app/models/spina/admin/conferences/presentation.rb @@ -15,6 +15,11 @@ module Conferences # - {#title} # - {#abstract} class Presentation < ApplicationRecord + include AttrJson::Record + include AttrJson::NestedAttributes + include Spina::Partable + include Spina::TranslatedContent + # @!attribute [rw] start_datetime # @return [ActiveSupport::TimeWithZone, nil] the presentation start time diff --git a/app/models/spina/admin/conferences/time_part.rb b/app/models/spina/admin/conferences/time_part.rb deleted file mode 100644 index f8bcd074..00000000 --- a/app/models/spina/admin/conferences/time_part.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module Spina - module Admin - module Conferences - # Time parts. - class TimePart < ApplicationRecord - has_many :page_parts, as: :page_partable - has_many :parts, as: :partable - has_many :layout_parts, as: :layout_partable - has_many :structure_parts, as: :structure_partable - end - end - end -end diff --git a/app/models/spina/admin/conferences/url_part.rb b/app/models/spina/admin/conferences/url_part.rb deleted file mode 100644 index ae9d692a..00000000 --- a/app/models/spina/admin/conferences/url_part.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module Spina - module Admin - module Conferences - # URL parts. The format is validated. - # - # = Validators - # HTTP(S) URL (using {HttpUrlValidator}):: {#content}. - # @see HttpUrlValidator - class UrlPart < ApplicationRecord - has_many :page_parts, as: :page_partable - has_many :parts, as: :partable - has_many :layout_parts, as: :layout_partable - has_many :structure_parts, as: :structure_partable - - validates :content, 'spina/admin/conferences/http_url': true, allow_blank: true - end - end - end -end diff --git a/app/models/spina/parts/admin/conferences/date.rb b/app/models/spina/parts/admin/conferences/date.rb new file mode 100644 index 00000000..5d4b1716 --- /dev/null +++ b/app/models/spina/parts/admin/conferences/date.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Spina + module Parts + module Admin + module Conferences + # Date parts, without associated times. + class Date < Spina::Parts::Base + attr_json :content, :date + end + end + end + end +end diff --git a/app/models/spina/parts/admin/conferences/email_address.rb b/app/models/spina/parts/admin/conferences/email_address.rb new file mode 100644 index 00000000..b678a326 --- /dev/null +++ b/app/models/spina/parts/admin/conferences/email_address.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Spina + module Parts + module Admin + module Conferences + # Email address parts. The format is validated. + # + # = Validators + # Email address (using {EmailAddressValidator}):: {#content}. + # @see EmailAddressValidator + class EmailAddress < Spina::Parts::Base + attr_json :content, :string + + validates :content, 'spina/admin/conferences/email_address': true, allow_blank: true + end + end + end + end +end diff --git a/app/models/spina/parts/admin/conferences/time.rb b/app/models/spina/parts/admin/conferences/time.rb new file mode 100644 index 00000000..28421703 --- /dev/null +++ b/app/models/spina/parts/admin/conferences/time.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Spina + module Parts + module Admin + module Conferences + # Time parts. + class Time < Spina::Parts::Base + attr_json :content, :time + end + end + end + end +end diff --git a/app/models/spina/parts/admin/conferences/url.rb b/app/models/spina/parts/admin/conferences/url.rb new file mode 100644 index 00000000..b7a2765d --- /dev/null +++ b/app/models/spina/parts/admin/conferences/url.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Spina + module Parts + module Admin + module Conferences + # URL parts. The format is validated. + # + # = Validators + # HTTP(S) URL (using {HttpUrlValidator}):: {#content}. + # @see HttpUrlValidator + class Url < Spina::Parts::Base + attr_json :content, :string + + validates :content, 'spina/admin/conferences/http_url': true, allow_blank: true + end + end + end + end +end diff --git a/app/views/spina/admin/conferences/conferences/_form_parts.html.haml b/app/views/spina/admin/conferences/conferences/_form_parts.html.haml index c62f122c..c9051b65 100644 --- a/app/views/spina/admin/conferences/conferences/_form_parts.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_parts.html.haml @@ -1,15 +1,10 @@ #parts.tab-content .well .horizontal-form - = f.fields_for :parts do |ff| - = ff.hidden_field :id + = f.fields_for :"#{@locale}_content", @parts do |ff| + = ff.hidden_field :type, value: ff.object.class.name = ff.hidden_field :title - = ff.hidden_field :partable_type = ff.hidden_field :name .horizontal-form-group.page-part{ data: { name: ff.object.name } } - - case ff.object.partable_type - - when 'Spina::Structure' - = render 'form_structure', f: ff - - else - = render "spina/admin/partables/#{partable_type_partial_namespace(ff.object.partable_type)}/form", f: ff + = render "spina/admin/parts/#{parts_partial_namespace(ff.object.class.name)}/form", f: ff diff --git a/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml b/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml index fa57be38..4b1521f4 100644 --- a/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml +++ b/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml @@ -12,24 +12,20 @@ .horizontal-form-group .horizontal-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :logo .horizontal-form-content{ data: { controller: 'image-form' } } - = link_to admin_media_picker_path(selected_ids: [f.object.logo_id], hidden_field_id: 'media_picker_logo_id'), remote: true, class: %w[media_picker clearfix] do - .placeholder - %span.button.button-small.button-round - %i.icon.icon-dots - = t 'spina.images.choose_image' - - - if f.object.logo&.file&.attached? - %br/ - - %span.button.button-small.button-round{ data: { action: 'click->image-form#remove', target: 'image-form.button' } } - %i.icon.icon-trash - = t 'spina.images.remove_image' - - - if f.object.logo&.file&.attached? - .image{ data: { target: 'image-form.image' } }= image_tag variant(f.object.logo.file, resize: '300x300^', crop: '300x300+0+0') - - = f.hidden_field :logo_id, data: { hidden_field_id: 'media_picker_logo_id', target: 'image-form.field' } - + .page-form-media-picker + %div{ style: 'width: 100%' } + = link_to admin_media_picker_path(selected_ids: [f.object.logo_id], input: "media_picker_#{f.object.object_id}", mode: 'single'), remote: true, class: 'image', data: { target: 'image-form.image' } do + .page-form-media-picker-placeholder= t 'spina.images.choose_image' + %div{ id: "media_picker_#{f.object.object_id}" } + = f.hidden_field :logo_id, data: { target: 'image-form.imageId' } + = f.hidden_field :logo_signed_blob_id, value: f.object.logo&.file&.signed_id, data: {target: 'image-form.signedBlobId'} + = f.hidden_field :logo_filename, value: f.object.logo&.file&.filename, data: {target: 'image-form.filename'} + %div{ style: 'width: 200px; height: 150px; overflow: hidden' } + - if f.object.logo.present? + = image_tag main_app.url_for(f.object.logo.variant(resize: '400x300^', crop: '400x300+0+0')), width: 200, height: 150 + + = button_tag type: :default, class: 'button button-small button-default', data: { action: 'image-form#remove' } do + %i.icon.icon-cross{ style: 'margin: 0; font-size: 10px' } - unless @institution.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_institution_path(@institution), method: :delete, data: { confirm: t('.delete_confirmation', institution: @institution.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml b/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml index d032623d..39f76073 100644 --- a/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml +++ b/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml @@ -4,22 +4,13 @@ = Spina::Admin::Conferences::PresentationAttachment.human_attribute_name :attachment_type .horizontal-form-content .select-dropdown - = f.label :attachment_type, Spina::Admin::Conferences::PresentationAttachment.human_attribute_name(:attachment_type) = f.collection_select :attachment_type_id, Spina::Admin::Conferences::PresentationAttachmentType.all, :id, :name, {}, data: { action: 'spina--admin--conferences--presentation-attachments-form#updateType' } .structure-form-part .horizontal-form-label = Spina::Admin::Conferences::PresentationAttachment.human_attribute_name :attachment - .horizontal-form-content - = link_to select_admin_attachments_path(f.object_name, selected_attachment_id: f.object.attachment.try(:id), hidden_field_id: "presentation_attachments_attributes_#{f.index}_attachment_id"), remote: true, class: "media_picker" do - .placeholder - %span.button.button-small.button-round - %i.icon.icon-dots - = t('spina.choose_from_library') - - - if f.object.attachment && f.object.attachment.file.present? - .attachment= f.object.attachment.name - - = f.hidden_field :attachment_id, data: { hidden_field_id: "presentation_attachments_attributes_#{f.index}_attachment_id" } + .horizontal-form-content{ data: { controller: "attachment-picker" } } + .select-dropdown + = f.collection_select :attachment_id, Spina::Attachment.sorted, :id, :name, { include_blank: t("spina.attachments.choose_attachment") } = f.hidden_field :id diff --git a/app/views/spina/admin/partables/admin/conferences/date_parts/_form.html.haml b/app/views/spina/admin/partables/admin/conferences/date_parts/_form.html.haml deleted file mode 100644 index 200c8ea0..00000000 --- a/app/views/spina/admin/partables/admin/conferences/date_parts/_form.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -.horizontal-form-label - = f.object.title -.horizontal-form-content - = f.fields_for :partable, f.object.partable do |ff| - = ff.date_field :content diff --git a/app/views/spina/admin/partables/admin/conferences/email_address_parts/_form.html.haml b/app/views/spina/admin/partables/admin/conferences/email_address_parts/_form.html.haml deleted file mode 100644 index 77f75956..00000000 --- a/app/views/spina/admin/partables/admin/conferences/email_address_parts/_form.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -.horizontal-form-label - = f.object.title -.horizontal-form-content - = f.fields_for :partable, f.object.partable do |ff| - = ff.email_field :content diff --git a/app/views/spina/admin/partables/admin/conferences/time_parts/_form.html.haml b/app/views/spina/admin/partables/admin/conferences/time_parts/_form.html.haml deleted file mode 100644 index ad7926d4..00000000 --- a/app/views/spina/admin/partables/admin/conferences/time_parts/_form.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -.horizontal-form-label - = f.object.title -.horizontal-form-content - = f.fields_for :partable, f.object.partable do |ff| - = ff.datetime_field :content diff --git a/app/views/spina/admin/partables/admin/conferences/url_parts/_form.html.haml b/app/views/spina/admin/partables/admin/conferences/url_parts/_form.html.haml deleted file mode 100644 index 45dab785..00000000 --- a/app/views/spina/admin/partables/admin/conferences/url_parts/_form.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -.horizontal-form-label - = f.object.title -.horizontal-form-content - = f.fields_for :partable, f.object.partable do |ff| - = ff.url_field :content diff --git a/app/views/spina/admin/parts/admin/conferences/dates/_form.html.haml b/app/views/spina/admin/parts/admin/conferences/dates/_form.html.haml new file mode 100644 index 00000000..587fbfe1 --- /dev/null +++ b/app/views/spina/admin/parts/admin/conferences/dates/_form.html.haml @@ -0,0 +1,2 @@ +.page-form-label= f.object.title +.page-form-control= f.date_field :content, placeholder: f.object.title diff --git a/app/views/spina/admin/parts/admin/conferences/email_addresses/_form.html.haml b/app/views/spina/admin/parts/admin/conferences/email_addresses/_form.html.haml new file mode 100644 index 00000000..bb40d8f9 --- /dev/null +++ b/app/views/spina/admin/parts/admin/conferences/email_addresses/_form.html.haml @@ -0,0 +1,2 @@ +.page-form-label= f.object.title +.page-form-control= f.email_field :content, placeholder: f.object.title diff --git a/app/views/spina/admin/parts/admin/conferences/times/_form.html.haml b/app/views/spina/admin/parts/admin/conferences/times/_form.html.haml new file mode 100644 index 00000000..473faeee --- /dev/null +++ b/app/views/spina/admin/parts/admin/conferences/times/_form.html.haml @@ -0,0 +1,2 @@ +.page-form-label= f.object.title +.page-form-control= f.datetime_field :content, placeholder: f.object.title diff --git a/app/views/spina/admin/parts/admin/conferences/urls/_form.html.haml b/app/views/spina/admin/parts/admin/conferences/urls/_form.html.haml new file mode 100644 index 00000000..a5c845eb --- /dev/null +++ b/app/views/spina/admin/parts/admin/conferences/urls/_form.html.haml @@ -0,0 +1,2 @@ +.page-form-label= f.object.title +.page-form-control= f.url_field :content, placeholder: f.object.title diff --git a/config/locales/en.yml b/config/locales/en.yml index a5c0d334..f30d1aac 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -39,6 +39,7 @@ en: images: Images # This translation is apparently not provided by Spina for some reason images: delete: Delete # Ditto + choose: Choose admin: conferences: title: Conferences diff --git a/db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb b/db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb new file mode 100644 index 00000000..ef80bc14 --- /dev/null +++ b/db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddJsonAttributesToSpinaConferencesPresentations < ActiveRecord::Migration[6.1] + def change + add_column :spina_conferences_presentations, :json_attributes, :jsonb + end +end diff --git a/db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb b/db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb new file mode 100644 index 00000000..070c9994 --- /dev/null +++ b/db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddJsonAttributesToSpinaConferencesConferences < ActiveRecord::Migration[6.1] + def change + add_column :spina_conferences_conferences, :json_attributes, :jsonb + end +end diff --git a/db/migrate/20210315164411_convert_partables_to_json.rb b/db/migrate/20210315164411_convert_partables_to_json.rb new file mode 100644 index 00000000..33d7db7d --- /dev/null +++ b/db/migrate/20210315164411_convert_partables_to_json.rb @@ -0,0 +1,415 @@ +# frozen_string_literal: true + +# This migration converts table-based partables from Spina v1 to the new JSON-based parts in Spina v2. +# If you have custom partables you must modify this migration to ensure the conversion of your partables is handled appropriately +# by implementing convert_to_json! for your partables. + +# Reregistering parts necessary due to deserialization from JSON, where class instances from registration used +Spina::Part.all.delete_if { |part| Spina::Parts::Admin::Conferences.constants.include? :"#{part.name.demodulize}" } +Spina::Part.register(Spina::Parts::Admin::Conferences::Date) +Spina::Part.register(Spina::Parts::Admin::Conferences::EmailAddress) +Spina::Part.register(Spina::Parts::Admin::Conferences::Time) +Spina::Part.register(Spina::Parts::Admin::Conferences::Url) + +class ConvertPartablesToJson < ActiveRecord::Migration[6.1] + def up + announce 'converting partables to JSON parts' + Spina.config.locales.each do |locale| + I18n.with_locale(locale) do + say_with_time "Migrating content in locale #{I18n.locale}..." do + Spina::Page.in_batches.each_record do |page| + say "Migrating page parts for \"#{page.title}\"...", true + page.convert_page_parts_to_json! + end + Spina::Account.in_batches.each_record do |account| + say "Migrating layout parts for \"#{account.name}\"...", true + account.convert_layout_parts_to_json! + end + Spina::Admin::Conferences::Conference.in_batches.each_record do |conference| + say "Migrating parts for \"#{conference.name}\"...", true + conference.convert_parts_to_json! + end + Spina::Admin::Conferences::Presentation.in_batches.each_record do |presentation| + say "Migrating parts for \"#{presentation.title}\"...", true + presentation.convert_parts_to_json! + end + end + end + end + end + + def down + announce 'converting JSON parts to partables' + Spina.config.locales.each do |locale| + I18n.with_locale(locale) do + say_with_time "Migrating content in locale #{I18n.locale}..." do + Spina::Page.in_batches.each_record do |page| + say "Migrating JSON parts for \"#{page.title}\"...", true + page.convert_json_to_parts! + end + Spina::Account.in_batches.each_record do |account| + say "Migrating JSON parts for \"#{account.name}\"...", true + account.convert_json_to_parts! + end + Spina::Admin::Conferences::Conference.in_batches.each_record do |conference| + say "Migrating JSON parts for \"#{conference.name}\"...", true + conference.convert_json_to_parts! + end + Spina::Admin::Conferences::Presentation.in_batches.each_record do |presentation| + say "Migrating JSON parts for \"#{presentation.title}\"...", true + presentation.convert_json_to_parts! + end + end + end + end + end +end + +module Spina + class ImageCollectionsImage < Spina::ApplicationRecord + belongs_to :image + belongs_to :image_collection + end + + class AttachmentCollectionsAttachment < Spina::ApplicationRecord + belongs_to :attachment + belongs_to :attachment_collection + end + + class Attachment < ApplicationRecord + def convert_to_json! + Parts::Attachment.new(attachment_id: id, signed_blob_id: file.blob.signed_id, filename: file.blob.filename) + end + end + + class AttachmentCollection < ApplicationRecord + has_many :attachment_collection_attachments + has_many :attachments, through: :attachment_collection_attachments + + def convert_to_json! + Parts::Repeater.new(content: attachments.collect(&:convert_to_json!) + .collect { |attachment| RepeaterContent.new(parts: [attachment]) }) + end + end + + class Image < ApplicationRecord + def convert_to_json! + Parts::Image.new(image_id: id, signed_blob_id: file.blob.signed_id, filename: file.blob.filename) + end + end + + class ImageCollection < ApplicationRecord + has_many :image_collections_images + has_many :images, through: :image_collections_images + + def convert_to_json! + Parts::ImageCollection.new(images: images.order(:position).collect(&:convert_to_json!)) + end + end + + class Line < ApplicationRecord + extend Mobility + translates :content, fallbacks: true + + def convert_to_json! + Parts::Line.new(content: content) + end + end + + class Option < ApplicationRecord + def convert_to_json! + Parts::Option.new(content: content) + end + + private + + def content + I18n.t(['options', part.name, value].compact.join('.')) + end + + def part + page_part || layout_part || structure_part + end + end + + class Structure < ApplicationRecord + has_many :structure_items + has_one :page_part, as: :page_partable + has_one :layout_part, as: :layout_partable + has_one :part, as: :partable, class_name: 'Spina::Admin::Conferences::Part' + + def convert_to_json! + Parts::Repeater.new(content: structure_items.order(:position) + .collect(&:convert_to_json!) + .each { |structure_item| structure_item.name = present_part.name }) + end + + def present_part + page_part || layout_part || part + end + end + + class Text < ApplicationRecord + extend Mobility + translates :content, fallbacks: true + + def convert_to_json! + Parts::Text.new(content: content) + end + end + + class LayoutPart < ::Spina::ApplicationRecord + belongs_to :account + belongs_to :layout_partable, polymorphic: true + + def convert_to_json! + raise <<~MESSAGE unless layout_partable.respond_to? :convert_to_json! + Cannot convert an instance of #{layout_partable_type} to JSON. + You need to modify #{__FILE__} and implement `convert_to_json!` for this partable. + MESSAGE + + layout_partable.convert_to_json!.tap { |layout_partable| layout_partable.name = name } + end + end + + class PagePart < ::Spina::ApplicationRecord + belongs_to :page + belongs_to :page_partable, polymorphic: true + + def convert_to_json! + raise <<~MESSAGE unless page_partable.respond_to? :convert_to_json! + Cannot convert an instance of #{page_partable_type} to JSON. + You need to modify #{__FILE__} and implement `convert_to_json!` for this partable. + MESSAGE + + page_partable.convert_to_json!.tap { |page_partable| page_partable.name = name } + end + end + + class StructurePart < ::Spina::ApplicationRecord + belongs_to :structure_item + belongs_to :structure_partable, polymorphic: true + + def convert_to_json! + raise <<~MESSAGE unless structure_partable.respond_to? :convert_to_json! + Cannot convert an instance of #{structure_partable_type} to JSON. + You need to modify #{__FILE__} and implement `convert_to_json!` for this partable. + MESSAGE + + structure_partable.convert_to_json!.tap { |structure_partable| structure_partable.name = name } + end + end + + class Page < Spina::ApplicationRecord + has_many :page_parts + + def convert_page_parts_to_json! + page_parts.reject { |page_part| page_part.page_partable.nil? } + .collect(&:convert_to_json!) + .compact + .then { |parts| send(:"#{I18n.locale}_content").union(parts) } + .then { |parts| update("#{I18n.locale}_content": parts) } + end + + def convert_json_to_parts! + update(page_parts: send(:"#{I18n.locale}_content").collect(&:convert_to_partable!) + .compact + .collect { |partable| PagePart.new(page_partable: partable) }) + end + end + + class Account < Spina::ApplicationRecord + has_many :layout_parts + + def convert_layout_parts_to_json! + layout_parts.reject { |layout_part| layout_part.layout_partable.nil? } + .collect(&:convert_to_json!) + .compact + .then { |parts| send(:"#{I18n.locale}_content").union(parts) } + .then { |parts| update("#{I18n.locale}_content": parts) } + end + + def convert_json_to_parts! + update(layout_parts: send(:"#{I18n.locale}_content") + .collect(&:convert_to_partable!) + .compact + .collect { |partable| LayoutPart.new(layout_partable: partable) }) + end + end + + class StructureItem < Spina::ApplicationRecord + belongs_to :structure + has_many :structure_parts + + def convert_to_json! + Parts::RepeaterContent.new(parts: structure_parts.reject { |structure_part| structure_part.structure_partable.nil? } + .collect(&:convert_to_json!) + .compact) + end + end + + module Parts + class Attachment < Base + def convert_to_partable! + Spina::Attachment.find(attachment_id) + end + end + + class Image < Base + def convert_to_partable! + Spina::Image.find(image_id) + end + end + + class ImageCollection < Base + def convert_to_partable! + Spina::ImageCollection.new(images: images.collect(&:convert_to_part!)) + end + end + + class Line < Base + def convert_to_partable! + Spina::Line.new(content: content) + end + end + + class MultiLine < Base + def convert_to_partable! + Spina::Text.new(content: content) + end + end + + class Text < Base + def convert_to_partable! + Spina::Text.new(content: content) + end + end + + class Option < Base + def convert_to_partable! + Spina::Option.new(content: content) + end + end + + class Repeater < Base + def convert_to_partable! + Spina::Structure.new(structure_items: content.collect(&:convert_to_structure_item!)) + end + end + + class RepeaterContent < Base + def convert_to_structure_item! + Spina::StructureItem.new(structure_parts: parts.collect(&:convert_to_partable!) + .compact + .collect { |partable| StructurePart.new(structure_partable: partable) }) + end + end + + module Admin + module Conferences + class Date < Spina::Parts::Base + def convert_to_partable! + Spina::Admin::Conferences::DatePart.new(content: content) + end + end + + class EmailAddress < Spina::Parts::Base + def convert_to_partable! + Spina::Admin::Conferences::EmailAddressPart.new(content: content) + end + end + + class Time < Spina::Parts::Base + def convert_to_partable! + Spina::Admin::Conferences::TimePart.new(content: content) + end + end + + class Url < Spina::Parts::Base + def convert_to_partable! + Spina::Admin::Conferences::UrlPart.new(content: content) + end + end + end + end + end + + module Admin + module Conferences + + class DatePart < ApplicationRecord + def convert_to_json! + Spina::Parts::Admin::Conferences::Date.new(content: content) + end + end + + class EmailAddressPart < ApplicationRecord + def convert_to_json! + Spina::Parts::Admin::Conferences::EmailAddress.new(content: content) + end + end + + class TimePart < ApplicationRecord + def convert_to_json! + Spina::Parts::Admin::Conferences::Time.new(content: content) + end + end + + class UrlPart < ApplicationRecord + def convert_to_json! + Spina::Parts::Admin::Conferences::Url.new(content: content) + end + end + + class Part < ApplicationRecord + belongs_to :pageable, polymorphic: true + belongs_to :partable, polymorphic: true + + def convert_to_json! + raise <<~MESSAGE unless partable.respond_to? :convert_to_json! + Cannot convert an instance of #{partable_type} to JSON. + You need to modify #{__FILE__} and implement `convert_to_json!` for this partable. + MESSAGE + + partable.convert_to_json!.tap { |partable| partable.name = name } + end + end + + class Conference < ApplicationRecord + has_many :parts, as: :pageable + + def convert_parts_to_json! + parts.reject { |part| part.partable.nil? } + .collect(&:convert_to_json!) + .compact + .then { |parts| send(:"#{I18n.locale}_content").union(parts) } + .then { |parts| update("#{I18n.locale}_content": parts) } + end + + def convert_json_to_parts! + update(parts: send(:"#{I18n.locale}_content").collect(&:convert_to_partable!) + .compact + .collect { |partable| Part.new(partable: partable) }) + end + end + + class Presentation < ApplicationRecord + has_many :parts, as: :pageable + + def convert_parts_to_json! + parts.reject { |part| part.partable.nil? } + .collect(&:convert_to_json!) + .compact + .then { |parts| send(:"#{I18n.locale}_content").union(parts) } + .then { |parts| update("#{I18n.locale}_content": parts) } + end + + def convert_json_to_parts! + update(parts: send(:"#{I18n.locale}_content").collect(&:convert_to_partable!) + .compact + .collect { |partable| Part.new(partable: partable) }) + end + end + end + end +end diff --git a/lib/spina/admin/conferences/engine.rb b/lib/spina/admin/conferences/engine.rb index 18c97acc..5ed56886 100644 --- a/lib/spina/admin/conferences/engine.rb +++ b/lib/spina/admin/conferences/engine.rb @@ -16,6 +16,11 @@ class Engine < ::Rails::Engine end config.after_initialize do + Spina::Part.register(Spina::Parts::Admin::Conferences::Date) + Spina::Part.register(Spina::Parts::Admin::Conferences::EmailAddress) + Spina::Part.register(Spina::Parts::Admin::Conferences::Time) + Spina::Part.register(Spina::Parts::Admin::Conferences::Url) + ActiveSupport::Deprecation .new('2.0', 'Spina::Admin::Conferences') .tap { |deprecator| deprecator.deprecate_methods(Conference, to_ics: :to_event) } diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb index 07effb7e..4165e77b 100644 --- a/test/application_system_test_case.rb +++ b/test/application_system_test_case.rb @@ -14,3 +14,5 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :selenium, using: :headless_chrome, screen_size: [1400, 800] end + +Capybara.default_max_wait_time = 5 diff --git a/test/controllers/spina/admin/conferences/conferences_controller_test.rb b/test/controllers/spina/admin/conferences/conferences_controller_test.rb index 4c8bd735..ca870ed1 100644 --- a/test/controllers/spina/admin/conferences/conferences_controller_test.rb +++ b/test/controllers/spina/admin/conferences/conferences_controller_test.rb @@ -14,7 +14,7 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa @empty_conference = spina_admin_conferences_conferences :empty_conference @user = spina_users :joe @rovinj_image = spina_images(:rovinj) - @dubrovnik_image = spina_images(:dubrovnik) + @logo = spina_images(:logo) post admin_sessions_url, params: { email: @user.email, password: 'password' } end @@ -178,67 +178,58 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa end test 'should save generic part' do - attributes = @conference.attributes.merge(start_date: @conference.start_date, finish_date: @conference.finish_date, - name: @conference.name, parts_attributes: - @conference.parts.collect do |part| - part.attributes.merge({ 'partable_attributes' => part.partable.attributes }) - end) - attributes[:parts_attributes].find { |part| part['name'] == 'submission_text' } - .then { |part| part['partable_attributes']['content'] = 'Dolor sit amen' } - assert_changes -> { @conference.content('submission_text') }, from: 'Lorem ipsum dolor sit amet', to: 'Dolor sit amen' do - patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream + attributes = @conference.attributes + attributes[:start_date] = @conference.start_date + attributes[:finish_date] = @conference.finish_date + attributes[:name] = @conference.name + attributes[:'en-GB_content_attributes'] = [ + { title: 'Submission text', name: 'submission_text', content: 'Dolor sit amen', type: 'Spina::Parts::Line' } + ] + assert_changes -> { @conference.reload.content(:submission_text) }, from: 'Lorem ipsum', to: 'Dolor sit amen' do + patch admin_conferences_conference_url(@conference), params: { conference: attributes } end end test 'should save generic structure part' do - attributes = @conference.attributes.merge(start_date: @conference.start_date, finish_date: @conference.finish_date, - name: @conference.name, parts_attributes: - @conference.parts.collect do |part| - part.attributes.merge({ 'partable_attributes' => part.partable.attributes }) - end) - sponsors = @conference.parts.find_by(name: 'sponsors') - attributes[:parts_attributes].find { |part| part['name'] == 'sponsors' }.then do |part| - part['partable_attributes']['structure_items_attributes'] = sponsors.partable.structure_items.collect do |structure_item| - structure_item.attributes.merge({ 'structure_parts_attributes' => structure_item.structure_parts.collect do |structure_part| - structure_part.attributes.merge({ 'partable_attributes' => structure_part.partable.attributes }) - end }) - end - end - attributes[:parts_attributes].find { |part| part['name'] == sponsors.name }.then do |part| - part['partable_attributes']['structure_items_attributes'] - .first['structure_parts_attributes'] - .find { |structure_part| structure_part['name'] == 'name' } - .then { |structure_part| structure_part['partable_attributes']['content'] = 'Test' } - end - assert_changes -> { @conference.content('sponsors').structure_items.first.content('name') }, - from: 'Lorem ipsum dolor sit amet', to: 'Test' do + attributes = @conference.attributes + attributes[:start_date] = @conference.start_date + attributes[:finish_date] = @conference.finish_date + attributes[:name] = @conference.name + attributes[:'en-GB_content_attributes'] = [ + { title: 'Sponsors', name: 'sponsors', type: 'Spina::Parts::Repeater', content_attributes: + [ + { title: 'Sponsors', name: 'sponsors', parts_attributes: + [ + { title: 'Name', name: 'name', content: 'Another sponsor', type: 'Spina::Parts::Line' } + ] + } + ] + } + ] + assert_changes -> { @conference.reload.content(:sponsors).first.content('name') }, from: 'Some sponsor', to: 'Another sponsor' do patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream end end test 'should save structure part image' do - attributes = @conference.attributes.merge(start_date: @conference.start_date, finish_date: @conference.finish_date, - name: @conference.name, parts_attributes: - @conference.parts.collect do |part| - part.attributes.merge({ 'partable_attributes' => part.partable.attributes }) - end) - sponsors = @conference.parts.find_by(name: 'sponsors') - attributes[:parts_attributes].find { |part| part['name'] == 'sponsors' }.then do |part| - part['partable_attributes']['structure_items_attributes'] = sponsors.partable.structure_items.collect do |structure_item| - structure_item.attributes.merge({ 'structure_parts_attributes' => structure_item.structure_parts.collect do |structure_part| - structure_part.attributes.merge({ 'partable_attributes' => structure_part.partable.attributes }) - end }) - end - end - attributes[:parts_attributes].find { |part| part['name'] == sponsors.name }.then do |part| - part['partable_attributes']['structure_items_attributes'] - .first['structure_parts_attributes'] - .find { |structure_part| structure_part['name'] == 'logo' } - .tap { |structure_part| structure_part.delete('partable_attributes') } - .then { |structure_part| structure_part['partable_id'] = @rovinj_image.id } - end - assert_changes -> { @conference.content('sponsors').structure_items.first.content('logo') }, - from: @dubrovnik_image, to: @rovinj_image do + attributes = @conference.attributes + attributes[:start_date] = @conference.start_date + attributes[:finish_date] = @conference.finish_date + attributes[:name] = @conference.name + attributes[:'en-GB_content_attributes'] = [ + { title: 'Sponsors', name: 'sponsors', type: 'Spina::Parts::Repeater', content_attributes: + [ + { title: 'Sponsors', name: 'sponsors', parts_attributes: + [ + { title: 'Logo', name: 'logo', type: 'Spina::Parts::Image', image_id: @rovinj_image.id, filename: 'logo.jpeg', + signed_blob_id: '', alt: 'Logo' } + ] + } + ] + } + ] + assert_changes -> { @conference.reload.content(:sponsors).first.content(:logo).spina_image }, + from: @logo, to: @rovinj_image do patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream end end diff --git a/test/dummy/config/initializers/themes/default.rb b/test/dummy/config/initializers/themes/default.rb index bf6fcf7c..915ce0e7 100644 --- a/test/dummy/config/initializers/themes/default.rb +++ b/test/dummy/config/initializers/themes/default.rb @@ -4,178 +4,149 @@ theme.name = 'default' theme.title = 'Default' - theme.page_parts = [{ + theme.layout_parts = %w[current_conference_alert] + + theme.parts = [{ name: 'text', title: 'Text', - partable_type: 'Spina::Text' + part_type: 'Spina::Parts::Text' }, { name: 'gallery', title: 'Gallery', - partable_type: 'Spina::ImageCollection' + part_type: 'Spina::Parts::ImageCollection' }, { name: 'constitution', title: 'Constitution', - partable_type: 'Spina::Attachment' + part_type: 'Spina::Parts::Attachment' }, { name: 'slides', title: 'Slides', - partable_type: 'Spina::Attachment' + part_type: 'Spina::Parts::Attachment' }, { name: 'handout', title: 'Handout', - partable_type: 'Spina::Attachment' + part_type: 'Spina::Parts::Attachment' }, { name: 'poster', title: 'Poster', - partable_type: 'Spina::Attachment' + part_type: 'Spina::Parts::Attachment' }, { name: 'partner_societies', title: 'Partner societies', - partable_type: 'Spina::Structure' + part_type: 'Spina::Parts::Repeater', + parts: %w[name logo description] }, { name: 'minutes', title: 'Minutes', - partable_type: 'Spina::Structure' + part_type: 'Spina::Parts::Repeater', + parts: %w[attachment] }, { name: 'contact', title: 'Contact', - partable_type: 'Spina::Text' + part_type: 'Spina::Parts::Text' }, { name: 'socials', title: 'Socials', - partable_type: 'Spina::Structure' + part_type: 'Spina::Parts::Repeater', + parts: %w[name location description] }, { name: 'meetings', title: 'Meetings', - partable_type: 'Spina::Structure' - }, { - name: 'submission_text', - title: 'Submission text', - partable_type: 'Spina::Line' + part_type: 'Spina::Parts::Repeater', + parts: %w[name location description] }, { name: 'committee_bios', title: 'Committee bios', - partable_type: 'Spina::Structure' + part_type: 'Spina::Parts::Repeater', + parts: %w[name role bio profile_picture] }, { name: 'sponsors', title: 'Sponsors', - partable_type: 'Spina::Structure' - }] - - theme.layout_parts = [{ + part_type: 'Spina::Parts::Repeater', + parts: %w[name website logo] + }, { name: 'current_conference_alert', title: 'Alert', - partable_type: 'Spina::Line' - }] - - theme.structures = [{ - name: 'partner_societies', - structure_parts: [{ - name: 'name', - title: 'Name', - partable_type: 'Spina::Line' - }, { - name: 'logo', - title: 'Logo', - partable_type: 'Spina::Image' - }, { - name: 'description', - title: 'Description', - partable_type: 'Spina::Text' - }] + part_type: 'Spina::Parts::Line' }, { - name: 'minutes', - structure_parts: [{ - name: 'attachment', - title: 'Attachment', - partable_type: 'Spina::Attachment' - }] + name: 'name', + title: 'Name', + part_type: 'Spina::Parts::Line' }, { - name: 'socials', - structure_parts: [{ - name: 'name', - title: 'Name', - partable_type: 'Spina::Line' - }, { - name: 'location', - title: 'Location', - partable_type: 'Spina::Line' - }, { - name: 'description', - title: 'Description', - partable_type: 'Spina::Text' - }] + name: 'description', + title: 'Description', + part_type: 'Spina::Parts::Text' }, { - name: 'meetings', - structure_parts: [{ - name: 'name', - title: 'Name', - partable_type: 'Spina::Line' - }, { - name: 'location', - title: 'Location', - partable_type: 'Spina::Line' - }, { - name: 'description', - title: 'Description', - partable_type: 'Spina::Text' - }] + name: 'attachment', + title: 'Attachment', + part_type: 'Spina::Parts::Attachment' }, { - name: 'committee_bios', - structure_parts: [{ - name: 'name', - title: 'Name', - partable_type: 'Spina::Line' - }, { - name: 'role', - title: 'Role', - partable_type: 'Spina::Line' - }, { - name: 'bio', - title: 'Bio', - partable_type: 'Spina::Text' - }, { - name: 'profile_picture', - title: 'Profile picture', - partable_type: 'Spina::Image' - }] + name: 'location', + title: 'Location', + part_type: 'Spina::Parts::Line' }, { - name: 'sponsors', - structure_parts: [{ - name: 'name', - title: 'Name', - partable_type: 'Spina::Line' - }, { - name: 'logo', - title: 'Logo', - partable_type: 'Spina::Image' - }] - }] + name: 'role', + title: 'Role', + part_type: 'Spina::Parts::Line' + }, { + name: 'bio', + title: 'Bio', + part_type: 'Spina::Parts::Text' + }, { + name: 'profile_picture', + title: 'Profile picture', + part_type: 'Spina::Parts::Image' + }, { + name: 'website', + title: 'Website', + part_type: 'Spina::Parts::Admin::Conferences::Url' + }, { + name: 'logo', + title: 'Logo', + part_type: 'Spina::Parts::Image' + }, { + name: 'submission_url', + title: 'Submission URL', + part_type: 'Spina::Parts::Admin::Conferences::Url' + }, { + name: 'submission_email_address', + title: 'Submission email address', + part_type: 'Spina::Parts::Admin::Conferences::EmailAddress' + }, { + name: 'submission_date', + title: 'Submission date', + part_type: 'Spina::Parts::Admin::Conferences::Date' + }, { + name: 'submission_text', + title: 'Submission text', + part_type: 'Spina::Parts::Line' + } +] theme.view_templates = [{ name: 'homepage', title: 'Homepage', - page_parts: %w[gallery] + parts: %w[gallery] }, { name: 'information', title: 'Information', description: 'Contains general information', - page_parts: %w[text] + parts: %w[text] }, { name: 'committee', title: 'Committee', description: 'Contains committee bios', - page_parts: %w[text committee_bios] + parts: %w[text committee_bios] }, { name: 'about', title: 'About', description: 'Contains information about the society', - page_parts: %w[text constitution minutes partner_societies contact] + parts: %w[text constitution minutes partner_societies contact] }, { name: 'show', title: 'Blank', description: 'Blank template', - page_parts: [] + parts: %w[] }] theme.custom_pages = [{ @@ -200,6 +171,4 @@ }] theme.plugins = ['conferences'] - - theme.resources = [] end diff --git a/test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb b/test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb new file mode 100644 index 00000000..2210b670 --- /dev/null +++ b/test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb @@ -0,0 +1,6 @@ +# This migration comes from spina (originally 13) +class AddJsonAttributesToSpinaAccounts < ActiveRecord::Migration[5.2] + def change + add_column :spina_accounts, :json_attributes, :jsonb + end +end diff --git a/test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb b/test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb new file mode 100644 index 00000000..7b8abfbe --- /dev/null +++ b/test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb @@ -0,0 +1,6 @@ +# This migration comes from spina (originally 14) +class AddJsonAttributesToSpinaPages < ActiveRecord::Migration[5.2] + def change + add_column :spina_pages, :json_attributes, :jsonb + end +end diff --git a/test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb b/test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb new file mode 100644 index 00000000..0c935399 --- /dev/null +++ b/test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb @@ -0,0 +1,6 @@ +# This migration comes from spina (originally 15) +class AddSlugToSpinaResources < ActiveRecord::Migration[5.2] + def change + add_column :spina_resources, :slug, :jsonb + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 5815b9a6..75c297c8 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -12,7 +12,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20_210_121_162_757) do +ActiveRecord::Schema.define(version: 20_210_321_001_208) do # These are extensions that must be enabled in order to support this database enable_extension 'plpgsql' @@ -65,6 +65,7 @@ t.datetime 'created_at', null: false t.datetime 'updated_at', null: false t.boolean 'robots_allowed', default: false + t.jsonb 'json_attributes' end create_table 'spina_attachment_collections', id: :serial, force: :cascade do |t| @@ -97,6 +98,7 @@ t.daterange 'dates', null: false t.datetime 'created_at', null: false t.datetime 'updated_at', null: false + t.jsonb 'json_attributes' end create_table 'spina_conferences_conferences_delegates', id: false, force: :cascade do |t| @@ -263,6 +265,7 @@ t.datetime 'created_at', null: false t.datetime 'updated_at', null: false t.datetime 'start_datetime', null: false + t.jsonb 'json_attributes' t.index ['session_id'], name: 'index_spina_conferences_presentations_on_session_id' end @@ -433,6 +436,7 @@ t.integer 'position' t.boolean 'active', default: true t.integer 'resource_id' + t.jsonb 'json_attributes' t.index ['resource_id'], name: 'index_spina_pages_on_resource_id' end @@ -444,6 +448,7 @@ t.string 'order_by' t.datetime 'created_at', null: false t.datetime 'updated_at', null: false + t.jsonb 'slug' t.index ['parent_page_id'], name: 'index_spina_resources_on_parent_page_id' end diff --git a/test/fixtures/active_storage/attachments.yml b/test/fixtures/active_storage/attachments.yml new file mode 100644 index 00000000..f1bca3bf --- /dev/null +++ b/test/fixtures/active_storage/attachments.yml @@ -0,0 +1,46 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the "{}" from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# + +dubrovnik: + name: file + record: dubrovnik (Spina::Image) + blob: dubrovnik + +rovinj: + name: file + record: rovinj (Spina::Image) + blob: rovinj + +logo: + name: file + record: logo (Spina::Image) + blob: logo + +profile_picture: + name: file + record: profile_picture (Spina::Image) + blob: profile_picture + +handout: + name: file + record: handout (Spina::Attachment) + blob: handout + +slides: + name: file + record: slides (Spina::Attachment) + blob: slides + +minutes: + name: file + record: minutes (Spina::Attachment) + blob: minutes + +constitution: + name: file + record: constitution (Spina::Attachment) + blob: constitution diff --git a/test/fixtures/active_storage/blobs.yml b/test/fixtures/active_storage/blobs.yml new file mode 100644 index 00000000..525faa24 --- /dev/null +++ b/test/fixtures/active_storage/blobs.yml @@ -0,0 +1,15 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the "{}" from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# + +dubrovnik: <%= ActiveStorage::FixtureSet.blob filename: 'dubrovnik.jpeg' %> +rovinj: <%= ActiveStorage::FixtureSet.blob filename: 'rovinj.jpeg' %> +logo: <%= ActiveStorage::FixtureSet.blob filename: 'logo.png' %> +profile_picture: <%= ActiveStorage::FixtureSet.blob filename: 'profile_picture.jpg' %> +handout: <%= ActiveStorage::FixtureSet.blob filename: 'handout.pdf' %> +slides: <%= ActiveStorage::FixtureSet.blob filename: 'slides.pdf' %> +minutes: <%= ActiveStorage::FixtureSet.blob filename: 'minutes.pdf' %> +constitution: <%= ActiveStorage::FixtureSet.blob filename: 'constitution.pdf' %> diff --git a/test/fixtures/files/constitution.pdf b/test/fixtures/files/constitution.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/fixtures/files/logo.png b/test/fixtures/files/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8b3ec7ff1465676a6c10bab8ddeebf143c2d2ad3 GIT binary patch literal 87009 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 BbrP>y+AHr@1KhZyuy)G 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

Kk{I>m0PT!?$AR!%6q{aOLQ%}B|KxG1 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/spina/admin/conferences/conferences.yml b/test/fixtures/spina/admin/conferences/conferences.yml index a4b5a31b..3dd1d5da 100644 --- a/test/fixtures/spina/admin/conferences/conferences.yml +++ b/test/fixtures/spina/admin/conferences/conferences.yml @@ -6,9 +6,99 @@ # university_of_atlantis_2017: dates: !ruby/range 2017-04-07...2017-04-10 + json_attributes: + en-GB_content: + - name: text + title: Text + type: Spina::Parts::Text + content: +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> + - name: gallery + title: Gallery + type: Spina::Parts::ImageCollection + images: + - image_id: <%= ActiveRecord::FixtureSet.identify(:dubrovnik) %> + filename: dubrovnik.jpeg + signed_blob_id: + alt: Dubrovnik + - image_id: <%= ActiveRecord::FixtureSet.identify(:rovinj) %> + filename: rovinj.jpeg + signed_blob_id: + alt: Rovinj + - name: submission_url + title: Submission URL + type: Spina::Parts::Admin::Conferences::Url + content: https://www.ruby-lang.org + - name: submission_email_address + title: Submission email address + type: Spina::Parts::Admin::Conferences::EmailAddress + content: someone@someaddress.com + - name: submission_date + title: Submission date + type: Spina::Parts::Admin::Conferences::Date + content: 2019-01-01 + - name: submission_text + title: Submission text + type: Spina::Parts::Line + content: Lorem ipsum + - name: sponsors + title: Sponsors + type: Spina::Parts::Repeater + content: + - name: sponsors + title: Sponsors + parts: + - name: name + title: Name + type: Spina::Parts::Line + content: Some sponsor + - name: logo + title: Logo + type: Spina::Parts::Image + image_id: <%= ActiveRecord::FixtureSet.identify(:logo) %> + filename: logo.png + signed_blob_id: + alt: Logo + - name: website + title: Website + type: Spina::Parts::Admin::Conferences::Url + content: https://www.ruby-lang.org university_of_shangri_la_2018: dates: !ruby/range 2018-04-09...2018-04-12 + json_attributes: + en-GB_content: + - name: text + title: Text + type: Spina::Parts::Text + - name: gallery + title: Gallery + type: Spina::Parts::ImageCollection + - name: submission_url + title: Submission URL + type: Spina::Parts::Admin::Conferences::Url + - name: submission_email_address + title: Submission email address + type: Spina::Parts::Admin::Conferences::EmailAddress + - name: submission_date + title: Submission date + type: Spina::Parts::Admin::Conferences::Date + - name: submission_text + title: Submission text + type: Spina::Parts::Line + - name: sponsors + title: Sponsors + type: Spina::Parts::Repeater empty_conference: dates: !ruby/range 2018-04-09...2018-04-12 + json_attributes: + en-GB_content: + - name: sponsors + title: Sponsors + type: Spina::Parts::Repeater diff --git a/test/fixtures/spina/admin/conferences/date_parts.yml b/test/fixtures/spina/admin/conferences/date_parts.yml deleted file mode 100644 index 591b7fcd..00000000 --- a/test/fixtures/spina/admin/conferences/date_parts.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the '{}' from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -valid_date: - content: 2019-01-01 diff --git a/test/fixtures/spina/admin/conferences/email_address_parts.yml b/test/fixtures/spina/admin/conferences/email_address_parts.yml deleted file mode 100644 index 10965ddc..00000000 --- a/test/fixtures/spina/admin/conferences/email_address_parts.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the '{}' from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -valid_email_address: - content: someone@somewhere.com diff --git a/test/fixtures/spina/admin/conferences/institutions.yml b/test/fixtures/spina/admin/conferences/institutions.yml index 65a60263..a2eae5d0 100644 --- a/test/fixtures/spina/admin/conferences/institutions.yml +++ b/test/fixtures/spina/admin/conferences/institutions.yml @@ -5,10 +5,10 @@ # below each fixture, per the syntax in the comments below # university_of_atlantis: - logo: dubrovnik + logo: logo university_of_shangri_la: - logo: rovinj + logo: logo empty_institution: - logo: rovinj + logo: logo diff --git a/test/fixtures/spina/admin/conferences/parts.yml b/test/fixtures/spina/admin/conferences/parts.yml deleted file mode 100644 index f1cebb54..00000000 --- a/test/fixtures/spina/admin/conferences/parts.yml +++ /dev/null @@ -1,101 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -text: - name: text - title: Text - partable: lipsum (Spina::Text) - pageable: university_of_atlantis_2017 (Spina::Admin::Conferences::Conference) - -empty_text: - name: text - title: Text - partable_type: Spina::Text - pageable: university_of_shangri_la_2018 (Spina::Admin::Conferences::Conference) - -gallery_2017: - name: gallery - title: Gallery - partable: gallery (Spina::ImageCollection) - pageable: university_of_atlantis_2017 (Spina::Admin::Conferences::Conference) - -gallery_2018: - name: gallery - title: Gallery - partable_type: Spina::ImageCollection - pageable: university_of_shangri_la_2018 (Spina::Admin::Conferences::Conference) - -submission_url: - name: submission_url - title: Submission URL - partable: valid_url (Spina::Admin::Conferences::UrlPart) - pageable: university_of_atlantis_2017 (Spina::Admin::Conferences::Conference) - -empty_submission_url: - name: submission_url - title: Submission URL - partable_type: Spina::Admin::Conferences::UrlPart - pageable: university_of_shangri_la_2018 (Spina::Admin::Conferences::Conference) - -submission_email_address: - name: submission_email_address - title: Submission email address - partable: valid_email_address (Spina::Admin::Conferences::EmailAddressPart) - pageable: university_of_atlantis_2017 (Spina::Admin::Conferences::Conference) - -empty_submission_email_address: - name: submission_email_address - title: Submission email address - partable_type: Spina::Admin::Conferences::EmailAddressPart - pageable: university_of_shangri_la_2018 (Spina::Admin::Conferences::Conference) - -submission_date: - name: submission_date - title: Submission date - partable: valid_date (Spina::Admin::Conferences::DatePart) - pageable: university_of_atlantis_2017 (Spina::Admin::Conferences::Conference) - -empty_submission_date: - name: submission_date - title: Submission date - partable_type: Spina::Admin::Conferences::DatePart - pageable: university_of_shangri_la_2018 (Spina::Admin::Conferences::Conference) - -submission_text: - name: submission_text - title: Submission text - partable: lipsum (Spina::Line) - pageable: university_of_atlantis_2017 (Spina::Admin::Conferences::Conference) - -empty_submission_text: - name: submission_text - title: Submission text - partable_type: Spina::Line - pageable: university_of_shangri_la_2018 (Spina::Admin::Conferences::Conference) - -sponsors: - name: sponsors - title: Sponsors - partable: sponsors (Spina::Structure) - pageable: university_of_atlantis_2017 (Spina::Admin::Conferences::Conference) - -empty_sponsors: - name: sponsors - title: Sponsors - partable_type: Spina::Structure - pageable: university_of_shangri_la_2018 (Spina::Admin::Conferences::Conference) - -new_sponsors: - name: sponsors - title: Sponsors - partable_type: Spina::Structure - pageable: empty_conference (Spina::Admin::Conferences::Conference) - -time: - name: time - title: Time - partable: valid_time (Spina::Admin::Conferences::TimePart) - -email_address: - name: email_address - title: Email address - partable: valid_email_address (Spina::Admin::Conferences::EmailAddressPart) diff --git a/test/fixtures/spina/admin/conferences/time_parts.yml b/test/fixtures/spina/admin/conferences/time_parts.yml deleted file mode 100644 index 96be3b17..00000000 --- a/test/fixtures/spina/admin/conferences/time_parts.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the '{}' from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -valid_time: - content: 2019-12-15 2:59:43.10 diff --git a/test/fixtures/spina/admin/conferences/url_parts.yml b/test/fixtures/spina/admin/conferences/url_parts.yml deleted file mode 100644 index 73d4ef20..00000000 --- a/test/fixtures/spina/admin/conferences/url_parts.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the '{}' from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -valid_url: - content: https://www.ruby-lang.org diff --git a/test/fixtures/spina/attachments.yml b/test/fixtures/spina/attachments.yml index ab7b9b06..21fdb92e 100644 --- a/test/fixtures/spina/attachments.yml +++ b/test/fixtures/spina/attachments.yml @@ -7,3 +7,7 @@ handout: {} slides: {} + +minutes: {} + +constitution: {} diff --git a/test/fixtures/spina/image_collections.yml b/test/fixtures/spina/image_collections.yml deleted file mode 100644 index 40021656..00000000 --- a/test/fixtures/spina/image_collections.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -gallery: {} diff --git a/test/fixtures/spina/image_collections_images.yml b/test/fixtures/spina/image_collections_images.yml deleted file mode 100644 index c5531890..00000000 --- a/test/fixtures/spina/image_collections_images.yml +++ /dev/null @@ -1,15 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -dubrovnik: - image_collection: gallery - image: dubrovnik - position: 1 - -rovinj: - image_collection: gallery - image: rovinj - position: 2 diff --git a/test/fixtures/spina/images.yml b/test/fixtures/spina/images.yml index 50477b55..5f2aca39 100644 --- a/test/fixtures/spina/images.yml +++ b/test/fixtures/spina/images.yml @@ -7,3 +7,7 @@ dubrovnik: {} rovinj: {} + +logo: {} + +profile_picture: {} diff --git a/test/fixtures/spina/layout_parts.yml b/test/fixtures/spina/layout_parts.yml deleted file mode 100644 index ee6bcf5e..00000000 --- a/test/fixtures/spina/layout_parts.yml +++ /dev/null @@ -1,25 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -date: - name: date - title: Date - layout_partable: valid_date (Spina::Admin::Conferences::DatePart) - -url: - name: url - title: URL - layout_partable: valid_url (Spina::Admin::Conferences::UrlPart) - -email_address: - name: email_address - title: Email address - layout_partable: valid_email_address (Spina::Admin::Conferences::EmailAddressPart) - -time: - name: time - title: Time - layout_partable: valid_time (Spina::Admin::Conferences::TimePart) diff --git a/test/fixtures/spina/line/translations.yml b/test/fixtures/spina/line/translations.yml deleted file mode 100644 index a6a9bf57..00000000 --- a/test/fixtures/spina/line/translations.yml +++ /dev/null @@ -1,10 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -lipsum: - content: Lorem ipsum dolor sit amet - locale: en-GB - translated_model: lipsum diff --git a/test/fixtures/spina/lines.yml b/test/fixtures/spina/lines.yml deleted file mode 100644 index e14303ef..00000000 --- a/test/fixtures/spina/lines.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -lipsum: {} diff --git a/test/fixtures/spina/page_parts.yml b/test/fixtures/spina/page_parts.yml deleted file mode 100644 index 2ac2d3db..00000000 --- a/test/fixtures/spina/page_parts.yml +++ /dev/null @@ -1,86 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -about_page_text: - name: text - title: Text - page_partable: lipsum (Spina::Text) - page: about - -about_page_contact: - name: contact - title: Contact - page_partable: lipsum (Spina::Text) - page: about - -information_page_text: - name: text - title: Text - page_partable: lipsum (Spina::Text) - page: information - -committee_page_text: - name: text - title: Text - page_partable: lipsum (Spina::Text) - page: committee - -homepage_gallery: - name: gallery - title: Gallery - page_partable: gallery (Spina::ImageCollection) - page: homepage - -constitution: - name: constitution - title: Constitution - page_partable: constitution (Spina::Attachment) - page: about - -partner_societies: - name: partner_societies - title: Partner societies - page_partable: partner_societies (Spina::Structure) - page: about - -minutes: - name: minutes - title: Minutes - page_partable: minutes (Spina::Structure) - page: about - -contact: - name: contact - title: Contact - page_partable: lipsum (Spina::Text) - page: about - -committee_bios: - name: committee_bios - title: Committee bios - page_partable: committee_bios (Spina::Structure) - page: committee - -date: - name: date - title: Date - page_partable: valid_date (Spina::Admin::Conferences::DatePart) - -url: - name: url - title: URL - page_partable: valid_url (Spina::Admin::Conferences::UrlPart) - -email_address: - name: email_address - title: Email address - page_partable: valid_email_address (Spina::Admin::Conferences::EmailAddressPart) - -time: - name: time - title: Time - page_partable: valid_time (Spina::Admin::Conferences::TimePart) - diff --git a/test/fixtures/spina/pages.yml b/test/fixtures/spina/pages.yml index 396e3453..20740472 100644 --- a/test/fixtures/spina/pages.yml +++ b/test/fixtures/spina/pages.yml @@ -7,18 +7,167 @@ homepage: name: homepage view_template: homepage + json_attributes: + en_content: + - name: gallery + title: Gallery + type: Spina::Parts::ImageCollection + images: + - image_id: <%= ActiveRecord::FixtureSet.identify(:dubrovnik) %> + filename: dubrovnik.jpeg + signed_blob_id: + alt: Dubrovnik + - image_id: <%= ActiveRecord::FixtureSet.identify(:rovinj) %> + filename: rovinj.jpeg + signed_blob_id: + alt: Rovinj information: name: information view_template: information + json_attributes: + en_content: + - name: text + title: Text + type: Spina::Parts::Text + content: +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> about: name: about view_template: about + json_attributes: + en_content: + - name: text + title: Text + type: Spina::Parts::Text + content: +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> + - name: contact + title: Contact + type: Spina::Parts::Text + content: +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> + - name: constitution + title: Constitution + type: Spina::Parts::Attachment + attachment_id: <%= ActiveRecord::FixtureSet.identify(:constitution) %> + filename: constitution.pdf + signed_blob_id: + - name: partner_societies + title: Partner societies + type: Spina::Parts::Repeater + content: + - name: partner_societies + title: Partner societies + parts: + - name: name + title: Name + type: Spina::Parts::Line + content: + - name: logo + title: Logo + type: Spina::Parts::Image + attachment_id: minutes + filename: logo.png + signed_blob_id: + alt: Logo + - name: description + title: Description + type: Spina::Parts::Text + content: +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> + - name: minutes + title: Minutes + type: Spina::Parts::Repeater + content: + - name: minutes + title: Minutes + parts: + - name: attachment + title: Attachment + type: Spina::Parts::Attachment + attachment_id: <%= ActiveRecord::FixtureSet.identify(:minutes) %> + filename: minutes.pdf + signed_blob_id: + - name: contact + title: Contact + type: Spina::Parts::Text + content: +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> committee: name: committee view_template: committee + json_attributes: + en_content: + - name: text + title: Text + type: Spina::Parts::Text + content: +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> + - name: committee_bios + title: Committee bios + type: Spina::Parts::Repeater + content: + - name: committee_bios + title: Committee bios + parts: + - name: name + title: Name + type: Spina::Parts::Line + content: Joe Bloggs + - name: role + title: Role + type: Spina::Parts::Line + content: Stand-in + - name: bio + title: Bio + type: Spina::Parts::Text + content: +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. + Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. + Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis + ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc + augue.<\/div> + - name: profile_picture + title: Profile picture + type: Spina::Parts::Image + attachment_id: profile_picture + filename: profile_picture.jpg + signed_blob_id: + alt: Profile picture blank: name: blank diff --git a/test/fixtures/spina/structure_items.yml b/test/fixtures/spina/structure_items.yml deleted file mode 100644 index 4057f992..00000000 --- a/test/fixtures/spina/structure_items.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -sponsor: - structure: sponsors - -partner_society: - structure: partner_societies - -minutes: - structure: minutes - -committee_bio: - structure: committee_bios diff --git a/test/fixtures/spina/structure_parts.yml b/test/fixtures/spina/structure_parts.yml deleted file mode 100644 index 7347248b..00000000 --- a/test/fixtures/spina/structure_parts.yml +++ /dev/null @@ -1,91 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -sponsor_name: - name: name - title: Name - structure_item: sponsor - structure_partable: lipsum (Spina::Line) - -sponsor_logo: - name: logo - title: Logo - structure_item: sponsor - structure_partable: dubrovnik (Spina::Image) - -sponsor_website: - name: website - title: Website - structure_item: sponsor - structure_partable: valid_url (Spina::Admin::Conferences::UrlPart) - -partner_society_name: - name: name - title: Name - structure_item: partner_society - structure_partable: lipsum (Spina::Line) - -partner_society_logo: - name: logo - title: Logo - structure_item: partner_society - structure_partable: dubrovnik (Spina::Image) - -partner_society_description: - name: description - title: Description - structure_item: partner_society - structure_partable: lipsum (Spina::Text) - -minutes_attachment: - name: minutes - title: Minutes - structure_item: minutes - structure_partable: handout (Spina::Attachment) - -committee_bio_name: - name: name - title: Name - structure_item: committee_bio - structure_partable: lipsum (Spina::Line) - -committee_bio_role: - name: role - title: Role - structure_item: committee_bio - structure_partable: lipsum (Spina::Line) - -committee_bio: - name: bio - title: Bio - structure_item: committee_bio - structure_partable: lipsum (Spina::Text) - -committee_bio_profile_picture: - name: profile_picture - title: Profile picture - structure_item: committee_bio - structure_partable: dubrovnik (Spina::Image) - -date: - name: date - title: Date - structure_partable: valid_date (Spina::Admin::Conferences::DatePart) - -url: - name: url - title: URL - structure_partable: valid_url (Spina::Admin::Conferences::UrlPart) - -email_address: - name: email_address - title: Email address - structure_partable: valid_email_address (Spina::Admin::Conferences::EmailAddressPart) - -time: - name: time - title: Time - structure_partable: valid_time (Spina::Admin::Conferences::TimePart) diff --git a/test/fixtures/spina/structures.yml b/test/fixtures/spina/structures.yml deleted file mode 100644 index 8d96c404..00000000 --- a/test/fixtures/spina/structures.yml +++ /dev/null @@ -1,13 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -sponsors: {} - -partner_societies: {} - -minutes: {} - -committee_bios: {} diff --git a/test/fixtures/spina/text/translations.yml b/test/fixtures/spina/text/translations.yml deleted file mode 100644 index a671f0c7..00000000 --- a/test/fixtures/spina/text/translations.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -lipsum: - content: - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. - Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. - Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis - ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. - Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc - augue. - locale: en-GB - translated_model: lipsum - -lipsum_us: - content: - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. - Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. - Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis - ultricies et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. - Proin placerat, elit aliquam mattis laoreet, enim risus mollis nunc, at dapibus elit dolor in tortor. Sed sed nunc - augue. - locale: en - translated_model: lipsum diff --git a/test/fixtures/spina/texts.yml b/test/fixtures/spina/texts.yml deleted file mode 100644 index e14303ef..00000000 --- a/test/fixtures/spina/texts.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -lipsum: {} diff --git a/test/helpers/spina/admin/conferences/conferences_helper_test.rb b/test/helpers/spina/admin/conferences/conferences_helper_test.rb deleted file mode 100644 index 3020430c..00000000 --- a/test/helpers/spina/admin/conferences/conferences_helper_test.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' -require 'haml/template' -require 'capybara/minitest' - -module Spina - module Admin - module Conferences - class ConferencesHelperTest < ActionView::TestCase - include Capybara::Minitest::Assertions - include Haml::Helpers - include Spina::Admin::AdminHelper - - setup do - @structure_item = spina_structure_items(:sponsor) - @new_structure_item = StructureItem.new - @part = spina_admin_conferences_parts(:sponsors) - init_haml_helpers - end - - test 'generates link to add new structure item' do - controller.view_context_class.include Spina::Admin::PagesHelper - controller.view_context_class.include Spina::Engine.routes.url_helpers - builder = ActionView::Helpers::FormBuilder.new(:partable, @part.partable, self, {}) - self.output_buffer = new_custom_structure_item(builder, @part) - assert_link href: '#', class: %w[add_structure_item_fields button button-link] do |link| - assert_match(/[0-9]+/, link[:'data-id']) - assert_not_nil link[:'data-fields'] - link.assert_selector 'i', class: %w[icon icon-plus] - end - end - - test 'builds structure parts for existing structure item' do - @structure_item.parts.clear - assert_difference -> { @structure_item.parts.size }, 3 do - build_custom_structure_parts('sponsors', @structure_item) - end - assert @structure_item.parts.all?(&:valid?) - end - - test 'builds structure parts for new structure item' do - assert_difference -> { @new_structure_item.parts.size }, 3 do - build_custom_structure_parts('sponsors', @new_structure_item) - end - assert @new_structure_item.parts.all?(&:valid?) - end - - private - - def document_root_element - Nokogiri::HTML::Document.parse(@output_buffer).root - end - - def page - Capybara::Node::Simple.new(document_root_element) - end - end - end - end -end diff --git a/test/models/spina/admin/conferences/conference_test.rb b/test/models/spina/admin/conferences/conference_test.rb index d280d725..e7af90c0 100644 --- a/test/models/spina/admin/conferences/conference_test.rb +++ b/test/models/spina/admin/conferences/conference_test.rb @@ -36,11 +36,6 @@ class ConferenceTest < ActiveSupport::TestCase # rubocop:disable Metrics/ClassLe assert_empty @new_conference.events end - test 'conference has associated parts' do - assert_not_empty @conference.parts - assert_empty @new_conference.parts - end - test 'conference has associated sessions' do assert_not_empty @conference.sessions assert_empty @new_conference.sessions @@ -203,33 +198,6 @@ class ConferenceTest < ActiveSupport::TestCase # rubocop:disable Metrics/ClassLe @conference.reload end end - - test 'finds an existing part' do - assert_equal @conference.parts.find_by(name: 'text'), @conference.part(name: 'text') - end - - test 'initializes a new part' do - @conference.part(name: 'foo', partable_type: 'Spina::Line').then do |part| - assert_equal 'foo', part.name - assert_equal 'Spina::Line', part.partable_type - assert_kind_of Spina::Line, part.partable - end - end - - test 'recreates a partable' do - @conference.part(name: 'text').partable.destroy - assert_kind_of Spina::Text, @conference.part(name: 'text').partable - end - - test 'responds to content' do - assert_equal @conference.parts.find_by(name: 'text').content, @conference.content('text') - assert_nil @new_conference.content('text') - end - - test 'responds to has_content' do - assert @conference.has_content? 'text' - assert_not @new_conference.has_content? 'text' - end end end end diff --git a/test/models/spina/admin/conferences/date_part_test.rb b/test/models/spina/admin/conferences/date_part_test.rb deleted file mode 100644 index 6d46589c..00000000 --- a/test/models/spina/admin/conferences/date_part_test.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -module Spina - module Admin - module Conferences - class DatePartTest < ActiveSupport::TestCase - setup do - @date_part = spina_admin_conferences_date_parts :valid_date - @new_date_part = DatePart.new - end - - test 'date part has associated page parts' do - assert_not_empty @date_part.page_parts - assert_empty @new_date_part.page_parts - end - - test 'date part has associated parts' do - assert_not_empty @date_part.parts - assert_empty @new_date_part.parts - end - - test 'date part has associated layout parts' do - assert_not_empty @date_part.layout_parts - assert_empty @new_date_part.layout_parts - end - - test 'date part has associated structure parts' do - assert_not_empty @date_part.structure_parts - assert_empty @new_date_part.structure_parts - end - end - end - end -end diff --git a/test/models/spina/admin/conferences/email_address_part_test.rb b/test/models/spina/admin/conferences/email_address_part_test.rb deleted file mode 100644 index 1381823a..00000000 --- a/test/models/spina/admin/conferences/email_address_part_test.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -module Spina - module Admin - module Conferences - class EmailAddressPartTest < ActiveSupport::TestCase - setup do - @email_address_part = spina_admin_conferences_email_address_parts :valid_email_address - @new_email_address_part = EmailAddressPart.new - end - - test 'email address part has associated page parts' do - assert_not_empty @email_address_part.page_parts - assert_empty @new_email_address_part.page_parts - end - - test 'email address part has associated parts' do - assert_not_empty @email_address_part.parts - assert_empty @new_email_address_part.parts - end - - test 'email address part has associated layout parts' do - assert_not_empty @email_address_part.layout_parts - assert_empty @new_email_address_part.layout_parts - end - - test 'email address part has associated structure parts' do - assert_not_empty @email_address_part.structure_parts - assert_empty @new_email_address_part.structure_parts - end - - test 'email address must be email address' do - assert @email_address_part.valid? - assert_empty @email_address_part.errors[:content] - @email_address_part.content = 'John Doe, Example INC ' - assert @email_address_part.invalid? - assert_not_empty @email_address_part.errors[:content] - end - end - end - end -end diff --git a/test/models/spina/admin/conferences/part_test.rb b/test/models/spina/admin/conferences/part_test.rb deleted file mode 100644 index e4899500..00000000 --- a/test/models/spina/admin/conferences/part_test.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -module Spina - module Admin - module Conferences - class PartTest < ActiveSupport::TestCase - setup do - @part = spina_admin_conferences_parts :text - @empty_part = spina_admin_conferences_parts :empty_text - @new_part = Part.new - end - - test 'part has associated pageable' do - assert_not_nil @part.pageable - assert_nil @new_part.pageable - end - - test 'part has associated partable' do - assert_not_nil @part.partable - assert_nil @new_part.partable - end - - test 'pageable must not be empty' do - assert @part.valid? - assert_empty @part.errors[:pageable] - @part.pageable = nil - assert @part.invalid? - assert_not_empty @part.errors[:pageable] - end - - test 'partable must not be empty' do - assert @part.valid? - assert_empty @part.errors[:partable] - @part.partable = nil - assert @part.invalid? - assert_not_empty @part.errors[:partable_type] - end - - test 'name must be unique for pageable' do - assert @empty_part.valid? - assert_empty @empty_part.errors[:name] - @empty_part.pageable = @part.pageable - @empty_part.name = @part.name - assert @empty_part.invalid? - assert_not_empty @empty_part.errors[:name] - @empty_part.name = 'Lorem ipsum' - assert @empty_part.valid? - assert_empty @empty_part.errors[:name] - @empty_part.name = @part.name - @empty_part.pageable = spina_admin_conferences_conferences(:university_of_shangri_la_2018) - assert @empty_part.valid? - assert_empty @empty_part.errors[:name] - end - - test 'accepts nested attributes for partable' do - assert_changes '@part.partable.content' do - @part.partable_attributes = { content: 'Dolor sit amen' } - end - end - end - end - end -end diff --git a/test/models/spina/admin/conferences/time_part_test.rb b/test/models/spina/admin/conferences/time_part_test.rb deleted file mode 100644 index 9aec33ee..00000000 --- a/test/models/spina/admin/conferences/time_part_test.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -module Spina - module Admin - module Conferences - class TimePartTest < ActiveSupport::TestCase - setup do - @time_part = spina_admin_conferences_time_parts :valid_time - @new_time_part = TimePart.new - end - - test 'time part has associated page parts' do - assert_not_empty @time_part.page_parts - assert_empty @new_time_part.page_parts - end - - test 'time part has associated parts' do - assert_not_empty @time_part.parts - assert_empty @new_time_part.parts - end - - test 'time part has associated layout parts' do - assert_not_empty @time_part.layout_parts - assert_empty @new_time_part.layout_parts - end - - test 'time part has associated structure parts' do - assert_not_empty @time_part.structure_parts - assert_empty @new_time_part.structure_parts - end - end - end - end -end diff --git a/test/models/spina/admin/conferences/url_part_test.rb b/test/models/spina/admin/conferences/url_part_test.rb deleted file mode 100644 index ef1f431f..00000000 --- a/test/models/spina/admin/conferences/url_part_test.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -module Spina - module Admin - module Conferences - class UrlPartTest < ActiveSupport::TestCase - setup do - @url_part = spina_admin_conferences_url_parts :valid_url - @new_url_part = UrlPart.new - end - - test 'url part has associated page parts' do - assert_not_empty @url_part.page_parts - assert_empty @new_url_part.page_parts - end - - test 'url part has associated parts' do - assert_not_empty @url_part.parts - assert_empty @new_url_part.parts - end - - test 'url part has associated layout parts' do - assert_not_empty @url_part.layout_parts - assert_empty @new_url_part.layout_parts - end - - test 'url part has associated structure parts' do - assert_not_empty @url_part.structure_parts - assert_empty @new_url_part.structure_parts - end - - test 'URL must be HTTP(S) URL' do - assert @url_part.valid? - assert_empty @url_part.errors[:content] - @url_part.content = 'ftp://www.bbc.co.uk' - assert @url_part.invalid? - assert_not_empty @url_part.errors[:content], 'wrong protocol adds error' - @url_part.restore_attributes - @url_part.content = '\\' - assert @url_part.invalid? - assert_not_empty @url_part.errors[:content], 'malformed URL adds error' - end - end - end - end -end diff --git a/test/models/spina/parts/admin/conferences/date_test.rb b/test/models/spina/parts/admin/conferences/date_test.rb new file mode 100644 index 00000000..8f333f2b --- /dev/null +++ b/test/models/spina/parts/admin/conferences/date_test.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'test_helper' + +module Spina + module Parts + module Admin + module Conferences + class DateTest < ActiveSupport::TestCase + setup do + @date_part = Date.new(content: 10.days.from_now) + @new_date_part = Date.new + end + + test 'date has content' do + assert_not_nil @date_part.content + assert_nil @new_date_part.content + end + end + end + end + end +end diff --git a/test/models/spina/parts/admin/conferences/email_address_test.rb b/test/models/spina/parts/admin/conferences/email_address_test.rb new file mode 100644 index 00000000..ecd6fc23 --- /dev/null +++ b/test/models/spina/parts/admin/conferences/email_address_test.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'test_helper' + +module Spina + module Parts + module Admin + module Conferences + class EmailAddressTest < ActiveSupport::TestCase + setup do + @email_address_part = EmailAddress.new(content: 'someone@somewhere.com') + @new_email_address_part = EmailAddress.new + end + + test 'email address has content' do + assert_not_nil @email_address_part.content + assert_nil @new_email_address_part.content + end + + test 'email address must be email address' do + assert @email_address_part.valid? + assert_empty @email_address_part.errors[:content] + @email_address_part.content = 'John Doe, Example INC ' + assert @email_address_part.invalid? + assert_not_empty @email_address_part.errors[:content] + end + end + end + end + end +end diff --git a/test/models/spina/parts/admin/conferences/time_test.rb b/test/models/spina/parts/admin/conferences/time_test.rb new file mode 100644 index 00000000..9b0330b0 --- /dev/null +++ b/test/models/spina/parts/admin/conferences/time_test.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'test_helper' + +module Spina + module Parts + module Admin + module Conferences + class TimeTest < ActiveSupport::TestCase + setup do + @time_part = Time.new(content: 10.years.from_now) + @new_time_part = Time.new + end + + test 'time has content' do + assert_not_nil @time_part.content + assert_nil @new_time_part.content + end + end + end + end + end +end diff --git a/test/models/spina/parts/admin/conferences/url_test.rb b/test/models/spina/parts/admin/conferences/url_test.rb new file mode 100644 index 00000000..99994b88 --- /dev/null +++ b/test/models/spina/parts/admin/conferences/url_test.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'test_helper' + +module Spina + module Parts + module Admin + module Conferences + class UrlTest < ActiveSupport::TestCase + setup do + @url_part = Url.new(content: 'https://www.ruby-lang.org') + @new_url_part = Url.new + end + + test 'URL has content' do + assert_not_nil @url_part.content + assert_nil @new_url_part.content + end + + test 'URL must be HTTP(S) URL' do + assert @url_part.valid? + assert_empty @url_part.errors[:content] + @url_part.content = '\\' + assert @url_part.invalid? + assert_not_empty @url_part.errors[:content], 'malformed URL adds error' + @url_part.content = 'ftp://www.bbc.co.uk' + assert @url_part.invalid? + assert_not_empty @url_part.errors[:content], 'wrong protocol adds error' + end + end + end + end + end +end diff --git a/test/system/spina/admin/conferences/conferences_test.rb b/test/system/spina/admin/conferences/conferences_test.rb index 1ece582f..6227a4d6 100644 --- a/test/system/spina/admin/conferences/conferences_test.rb +++ b/test/system/spina/admin/conferences/conferences_test.rb @@ -39,10 +39,8 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas click_link class: %w[button button-link icon] within '#structure_form_pane_0' do fill_in id: /conference_events_attributes_[0-9]_name/, with: @conference.events.first.name - fill_in id: /conference_events_attributes_[0-9]_start_datetime/, - with: @conference.events.first.start_datetime - fill_in id: /conference_events_attributes_[0-9]_finish_datetime/, - with: @conference.events.first.finish_datetime + fill_in id: /conference_events_attributes_[0-9]_start_datetime/, with: @conference.events.first.start_datetime + fill_in id: /conference_events_attributes_[0-9]_finish_datetime/, with: @conference.events.first.finish_datetime fill_in id: /conference_events_attributes_[0-9]_location/, with: @conference.events.first.location fill_in_rich_text_area with: @conference.events.first.description end @@ -50,49 +48,43 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas Percy.snapshot page, name: 'Conferences form on create' click_on 'Parts' within '[data-name="text"]' do - fill_in_rich_text_area with: @conference.parts.find_by(name: 'text').partable.content + fill_in_rich_text_area with: @conference.content(:text) end within '[data-name="submission_url"]' do - fill_in with: @conference.parts.find_by(name: 'submission_url').partable.content + fill_in with: @conference.content(:submission_url) end within '[data-name="submission_email_address"]' do - fill_in with: @conference.parts.find_by(name: 'submission_email_address').partable.content + fill_in with: @conference.content(:submission_email_address) end within '[data-name="submission_date"]' do - fill_in with: @conference.parts.find_by(name: 'submission_date').partable.content + fill_in with: @conference.content(:submission_date) end within '[data-name="submission_text"]' do - fill_in with: @conference.parts.find_by(name: 'submission_text').partable.content + fill_in with: @conference.content(:submission_text) end within '[data-name="gallery"]' do - execute_script '$.fx.off = true;' - click_on 'Choose image' + first('.images .page-form-media-picker-placeholder').execute_script <<~JS + this.style.position = 'static' + JS + click_on 'Choose' end - within '#overlay', visible: true, style: { display: 'block' } do - first('.gallery .item:not(.item-uploader)').click - find('.gallery-select-sidebar').click_on 'Choose image' + within '.modal', visible: true, style: { display: 'block' } do + first('.media-picker-image').click + click_on 'Confirm selection (1)' end - assert_no_selector '#overlay' within '[data-name="sponsors"]' do click_link class: %w[button button-link] within id: /structure_form_pane_[0-9]+/ do - fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ - _structure_parts_attributes_0_partable_attributes_content/x, - with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts.find_by(name: 'name') - .partable.content - fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ - _structure_parts_attributes_2_partable_attributes_content/x, - with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts - .find_by(name: 'website').partable.content - execute_script '$.fx.off = true;' + fill_in id: /conference_en-GB_content_attributes_[0-9]+_content_attributes_[0-9]+_parts_attributes_0_content/x, + with: @conference.content(:sponsors).first.content(:name) + fill_in id: /conference_en-GB_content_attributes_[0-9]+_content_attributes_[0-9]+_parts_attributes_1_content/x, + with: @conference.content(:sponsors).first.content(:website) click_on 'Choose image' end end - within '#overlay', visible: true, style: { display: 'block' } do - first('.gallery .item:not(.item-uploader)').click - find('.gallery-select-sidebar').click_on 'Choose image' + within '.modal', visible: true, style: { display: 'block' } do + first('.media-picker-image').click end - assert_no_selector '#overlay' click_on 'Save conference' assert_text 'Conference saved' Percy.snapshot page, name: 'Conferences index on create' @@ -125,48 +117,42 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas end click_on 'Parts' within '[data-name="text"]' do - fill_in_rich_text_area with: @conference.parts.find_by(name: 'text').partable.content + fill_in_rich_text_area with: @conference.content(:text) end within '[data-name="submission_url"]' do - fill_in with: @conference.parts.find_by(name: 'submission_url').partable.content + fill_in with: @conference.content(:submission_url) end within '[data-name="submission_email_address"]' do - fill_in with: @conference.parts.find_by(name: 'submission_email_address').partable.content + fill_in with: @conference.content(:submission_email_address) end within '[data-name="submission_date"]' do - fill_in with: @conference.parts.find_by(name: 'submission_date').partable.content + fill_in with: @conference.content(:submission_date) end within '[data-name="submission_text"]' do - fill_in with: @conference.parts.find_by(name: 'submission_text').partable.content + fill_in with: @conference.content(:submission_text) end within '[data-name="gallery"]' do - execute_script '$.fx.off = true;' - click_on 'Choose image' + first('.images .page-form-media-picker-placeholder').execute_script <<~JS + this.style.position = 'static' + JS + click_on 'Choose' end - within '#overlay', visible: true, style: { display: 'block' } do - first('.gallery .item:not(.item-uploader)').click - find('.gallery-select-sidebar').click_on 'Choose image' + within '.modal', visible: true, style: { display: 'block' } do + first('.media-picker-image').click + click_on 'Confirm selection (1)' end - assert_no_selector '#overlay' within '[data-name="sponsors"]' do within id: /structure_form_pane_[0-9]+/ do - fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ - _structure_parts_attributes_0_partable_attributes_content/x, - with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts.find_by(name: 'name') - .partable.content - fill_in id: /conference_parts_attributes_[0-9]_partable_attributes_structure_items_attributes_[0-9]+ - _structure_parts_attributes_2_partable_attributes_content/x, - with: @conference.parts.find_by(name: 'sponsors').partable.structure_items.first.structure_parts - .find_by(name: 'website').partable.content - execute_script '$.fx.off = true;' + fill_in id: /conference_en-GB_content_attributes_[0-9]+_content_attributes_[0-9]+_parts_attributes_0_content/x, + with: @conference.content(:sponsors).first.content(:name) + fill_in id: /conference_en-GB_content_attributes_[0-9]+_content_attributes_[0-9]+_parts_attributes_1_content/x, + with: @conference.content(:sponsors).first.content(:website) click_on 'Choose image' end end - within '#overlay', visible: true, style: { display: 'block' } do - first('.gallery .item:not(.item-uploader)').click - find('.gallery-select-sidebar').click_on 'Choose image' + within '.modal', visible: true, style: { display: 'block' } do + first('.media-picker-image').click end - assert_no_selector '#overlay' click_on 'Save conference' assert_text 'Conference saved' Percy.snapshot page, name: 'Conferences index on update' @@ -180,12 +166,10 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas assert_selector '.breadcrumbs' do assert_text @empty_conference.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the conference #{@empty_conference.name}?" - Percy.snapshot page, name: 'Conferences delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the conference #{@empty_conference.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Conferences delete dialog' + end assert_text 'Conference deleted' assert_no_selector "tr[data-conference-id=\"#{@empty_conference.id}\"]" Percy.snapshot page, name: 'Conferences index on delete' diff --git a/test/system/spina/admin/conferences/delegates_test.rb b/test/system/spina/admin/conferences/delegates_test.rb index e67eaef6..0dce80ca 100644 --- a/test/system/spina/admin/conferences/delegates_test.rb +++ b/test/system/spina/admin/conferences/delegates_test.rb @@ -73,12 +73,10 @@ class DelegatesTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @delegate.full_name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the delegate #{@delegate.full_name}?" - Percy.snapshot page, name: 'Delegates delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the delegate #{@delegate.full_name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Delegates delete dialog' + end assert_text 'Delegate deleted' assert_no_selector "tr[data-delegate-id=\"#{@delegate.id}\"]" Percy.snapshot page, name: 'Delegates index on delete' diff --git a/test/system/spina/admin/conferences/dietary_requirements_test.rb b/test/system/spina/admin/conferences/dietary_requirements_test.rb index 904050ac..ed118380 100644 --- a/test/system/spina/admin/conferences/dietary_requirements_test.rb +++ b/test/system/spina/admin/conferences/dietary_requirements_test.rb @@ -61,12 +61,10 @@ class DietaryRequirementsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @dietary_requirement.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the dietary requirement #{@dietary_requirement.name}?" - Percy.snapshot page, name: 'Dietary requirements delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the dietary requirement #{@dietary_requirement.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Dietary requirements delete dialog' + end assert_text 'Dietary requirement deleted' assert_no_selector "tr[data-dietary-requirement-id=\"#{@dietary_requirement.id}\"]" Percy.snapshot page, name: 'Dietary requirements index on delete' diff --git a/test/system/spina/admin/conferences/institutions_test.rb b/test/system/spina/admin/conferences/institutions_test.rb index f257d539..b51f3d8d 100644 --- a/test/system/spina/admin/conferences/institutions_test.rb +++ b/test/system/spina/admin/conferences/institutions_test.rb @@ -26,7 +26,7 @@ class InstitutionsTest < ApplicationSystemTestCase Percy.snapshot page, name: 'Institutions index' end - test 'creating an institution' do # rubocop:disable Metrics/BlockLength + test 'creating an institution' do visit admin_conferences_institutions_path click_on 'New institution' assert_selector '.breadcrumbs' do @@ -34,13 +34,10 @@ class InstitutionsTest < ApplicationSystemTestCase end fill_in 'institution_name', with: @institution.name fill_in 'institution_city', with: @institution.city - execute_script '$.fx.off = true;' click_on 'Choose image' - within '#overlay', visible: true, style: { display: 'block' } do - first('.gallery .item:not(.item-uploader)').click - find('.gallery-select-sidebar').click_on 'Choose image' + within '.modal', visible: true, style: { display: 'block' } do + first('.media-picker-image').click end - assert_no_selector '#overlay' Percy.snapshot page, name: 'Institutions form on create' click_on 'Save institution' assert_text 'Institution saved' @@ -58,13 +55,10 @@ class InstitutionsTest < ApplicationSystemTestCase Percy.snapshot page, name: 'Institutions form on update' fill_in 'institution_name', with: @institution.name fill_in 'institution_city', with: @institution.city - page.execute_script '$.fx.off = true;' click_on 'Choose image' - within '#overlay', visible: true, style: { display: 'block' } do - first('.gallery .item:not(.item-uploader)').click - find('.gallery-select-sidebar').click_on 'Choose image' + within '.modal', visible: true, style: { display: 'block' } do + first('.media-picker-image').click end - assert_no_selector '#overlay' click_on 'Save institution' assert_text 'Institution saved' Percy.snapshot page, name: 'Institutions index on update' @@ -78,12 +72,10 @@ class InstitutionsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @empty_institution.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the institution #{@empty_institution.name}?" - Percy.snapshot page, name: 'Institutions delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the institution #{@empty_institution.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Institutions delete dialog' + end assert_text 'Institution deleted' assert_no_selector "tr[data-institution-id=\"#{@empty_institution.id}\"]" Percy.snapshot page, name: 'Institutions index on delete' diff --git a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb index fcee1323..1b2892ab 100644 --- a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb +++ b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb @@ -61,12 +61,10 @@ class PresentationAttachmentTypesTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @presentation_attachment_type.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the presentation attachment type #{@presentation_attachment_type.name}?" - Percy.snapshot page, name: 'Presentation attachment types delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the presentation attachment type #{@presentation_attachment_type.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Presentation attachment types delete dialog' + end assert_text 'Presentation attachment type deleted' assert_no_selector "tr[data-dietary-requirement-id=\"#{@presentation_attachment_type.id}\"]" Percy.snapshot page, name: 'Presentation attachment types index on delete' diff --git a/test/system/spina/admin/conferences/presentation_types_test.rb b/test/system/spina/admin/conferences/presentation_types_test.rb index 41350eb4..7698551f 100644 --- a/test/system/spina/admin/conferences/presentation_types_test.rb +++ b/test/system/spina/admin/conferences/presentation_types_test.rb @@ -66,12 +66,10 @@ class PresentationTypesTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @empty_presentation_type.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the presentation type #{@empty_presentation_type.name}?" - Percy.snapshot page, name: 'Presentation types delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the presentation type #{@empty_presentation_type.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Presentation types delete dialog' + end assert_text 'Presentation type deleted' assert_no_selector "tr[data-presentation-type-id=\"#{@empty_presentation_type.id}\"]" Percy.snapshot page, name: 'Presentation types index on delete' diff --git a/test/system/spina/admin/conferences/presentations_test.rb b/test/system/spina/admin/conferences/presentations_test.rb index a00d695d..4fa3c6b8 100644 --- a/test/system/spina/admin/conferences/presentations_test.rb +++ b/test/system/spina/admin/conferences/presentations_test.rb @@ -5,7 +5,7 @@ module Spina module Admin module Conferences - class PresentationsTest < ApplicationSystemTestCase # rubocop:disable Metrics/ClassLength + class PresentationsTest < ApplicationSystemTestCase setup do @presentation = spina_admin_conferences_presentations :asymmetry_and_antisymmetry @user = spina_users :joe @@ -25,7 +25,7 @@ class PresentationsTest < ApplicationSystemTestCase # rubocop:disable Metrics/Cl Percy.snapshot page, name: 'Presentations index' end - test 'creating a presentation' do # rubocop:disable Metrics/BlockLength + test 'creating a presentation' do visit admin_conferences_presentations_path click_on 'New presentation' assert_selector '.breadcrumbs' do @@ -43,16 +43,10 @@ class PresentationsTest < ApplicationSystemTestCase # rubocop:disable Metrics/Cl within '.presentation_attachment' do click_link class: %w[button button-link icon] within '#structure_form_pane_0' do - select @presentation.attachments.first.name, - from: 'presentation_attachments_attributes_0_attachment_type_id' - click_on 'Choose from library' + select @presentation.attachments.first.name, from: 'presentation_attachments_attributes_0_attachment_type_id' + select @presentation.attachments.first.attachment.name, from: 'presentation_attachments_attributes_0_attachment_id' end end - within '#overlay', visible: true, style: { display: 'block' } do - first('li').choose allow_label_click: true - click_on 'Insert document' - end - assert_no_selector '#overlay' Percy.snapshot page, name: 'Presentations form on create' click_on 'Save presentation' assert_text 'Presentation saved' @@ -81,16 +75,10 @@ class PresentationsTest < ApplicationSystemTestCase # rubocop:disable Metrics/Cl click_link class: %w[button button-link icon] find_link(href: '#structure_form_pane_2').click within '#structure_form_pane_2' do - select @presentation.attachments.second.name, - from: 'presentation_attachments_attributes_2_attachment_type_id' - click_on 'Choose from library' + select @presentation.attachments.second.name, from: 'presentation_attachments_attributes_2_attachment_type_id' + select @presentation.attachments.first.attachment.name, from: 'presentation_attachments_attributes_2_attachment_id' end end - within '#overlay', visible: true, style: { display: 'block' } do - first('li').choose allow_label_click: true - click_on 'Insert document' - end - assert_no_selector '#overlay' click_on 'Save presentation' assert_text 'Presentation saved' Percy.snapshot page, name: 'Presentations index on update' @@ -104,12 +92,10 @@ class PresentationsTest < ApplicationSystemTestCase # rubocop:disable Metrics/Cl assert_selector '.breadcrumbs' do assert_text @presentation.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the presentation #{@presentation.name}?" - Percy.snapshot page, name: 'Presentations delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the presentation #{@presentation.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Presentations delete dialog' + end assert_text 'Presentation deleted' assert_no_selector "tr[data-presentation-id=\"#{@presentation.id}\"]" Percy.snapshot page, name: 'Presentations index on delete' diff --git a/test/system/spina/admin/conferences/rooms_test.rb b/test/system/spina/admin/conferences/rooms_test.rb index a56c8557..fd2440c5 100644 --- a/test/system/spina/admin/conferences/rooms_test.rb +++ b/test/system/spina/admin/conferences/rooms_test.rb @@ -66,12 +66,10 @@ class RoomsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @empty_room.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the room #{@empty_room.name}?" - Percy.snapshot page, name: 'Rooms delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the room #{@empty_room.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Rooms delete dialog' + end assert_text 'Room deleted' assert_no_selector "tr[data-room-id=\"#{@empty_room.id}\"]" Percy.snapshot page, name: 'Rooms index on delete' diff --git a/test/system/spina/admin/conferences/sessions_test.rb b/test/system/spina/admin/conferences/sessions_test.rb index 379d8a00..041df5b7 100644 --- a/test/system/spina/admin/conferences/sessions_test.rb +++ b/test/system/spina/admin/conferences/sessions_test.rb @@ -70,12 +70,10 @@ class SessionsTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @empty_session.name end - page.execute_script '$.fx.off = true;' - click_on 'Permanently delete' - find '#overlay', visible: true, style: { display: 'block' } - assert_text "Are you sure you want to delete the session #{@empty_session.name}?" - Percy.snapshot page, name: 'Sessions delete dialog' - click_on 'Yes, I\'m sure' + accept_confirm "Are you sure you want to delete the session #{@empty_session.name}?" do + click_on 'Permanently delete' + Percy.snapshot page, name: 'Sessions delete dialog' + end assert_text 'Session deleted' assert_no_selector "tr[data-session-id=\"#{@empty_session.id}\"]" Percy.snapshot page, name: 'Sessions index on delete' diff --git a/test/test_helper.rb b/test/test_helper.rb index 14437482..0f4de1e9 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -58,3 +58,29 @@ class TestCase setup { I18n.locale = I18n.default_locale } end end + +module StorageHelpers + module ::ActiveStorage + class FixtureSet + include ActiveSupport::Testing::FileFixtures + include ActiveRecord::SecureToken + + def self.blob(filename:, **attributes) + new.prepare ActiveStorage::Blob.new(filename: filename, key: generate_unique_secure_token), **attributes + end + + def prepare(instance, **attributes) + io = file_fixture(instance.filename.to_s).open + instance.unfurl(io) + instance.assign_attributes(attributes) + instance.upload_without_unfurling(io) + + instance.attributes.transform_values { |value| value.is_a?(Hash) ? value.to_json : value }.compact.to_json + end + end + + ::ActiveStorage::FixtureSet.file_fixture_path = "#{ActiveSupport::TestCase.fixture_path}/files" + end +end + +ActiveRecord::FixtureSet.context_class.include StorageHelpers From fb28b4318e5091cc2f96b4b1f556686dc8930254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Tue, 6 Apr 2021 22:45:44 +0100 Subject: [PATCH 12/21] Replace multiple selects --- .../spina/admin/conferences/application.sass | 8 ----- .../_form_delegate_details.html.haml | 30 +++++++++++++++---- .../_form_presentation_details.html.haml | 15 +++++++--- config/locales/en.yml | 12 -------- .../spina/admin/conferences/delegates_test.rb | 6 ++-- .../admin/conferences/presentations_test.rb | 8 ++--- 6 files changed, 39 insertions(+), 40 deletions(-) diff --git a/app/assets/stylesheets/spina/admin/conferences/application.sass b/app/assets/stylesheets/spina/admin/conferences/application.sass index 073fa524..b1f2ca21 100644 --- a/app/assets/stylesheets/spina/admin/conferences/application.sass +++ b/app/assets/stylesheets/spina/admin/conferences/application.sass @@ -1,11 +1,3 @@ -.multiple.select-dropdown - z-index: 0 - &:before - content: none - select - padding: 11px 10px - width: 100% - .turbo-progress-bar @import spina/configuration background-color: $primary-color diff --git a/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml b/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml index b6c4e178..993a4276 100644 --- a/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml +++ b/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml @@ -24,15 +24,33 @@ .horizontal-form-group .horizontal-form-label - = Spina::Admin::Conferences::Delegate.human_attribute_name :conferences - %small= t '.multiple_conferences_selection_instructions_html' - .horizontal-form-content.multiple.select-dropdown= f.collection_select :conference_ids, Spina::Admin::Conferences::Conference.all, :id, :name, {}, { multiple: true, required: true } + = Spina::Admin::Conferences::Delegate.human_attribute_name :dietary_requirements + .horizontal-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :dietary_requirement_ids, Spina::Admin::Conferences::DietaryRequirement.all, :id, :name do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label .horizontal-form-group .horizontal-form-label - = Spina::Admin::Conferences::Delegate.human_attribute_name :dietary_requirements - %small= t '.multiple_dietary_requirements_selection_instructions_html' - .horizontal-form-content.multiple.select-dropdown= f.collection_select :dietary_requirement_ids, Spina::Admin::Conferences::DietaryRequirement.all, :id, :name, {}, { multiple: true, required: false } + = Spina::Admin::Conferences::Delegate.human_attribute_name :conferences + .horizontal-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :conference_ids, Spina::Admin::Conferences::Conference.all, :id, :name, {} do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label - unless @delegate.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_delegate_path(@delegate), method: :delete, data: { confirm: t('.delete_confirmation', delegate: @delegate.full_name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml index a113d16c..7f1425fd 100644 --- a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml +++ b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml @@ -27,11 +27,18 @@ .horizontal-form-content= render 'spina/admin/shared/rich_text_field', f: f, field: :abstract .horizontal-form-group - .horizontal-form-label - = Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - %small= t '.multiple_presenters_selection_instructions_html' + .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters .horizontal-form-content - .multiple.select-dropdown= f.collection_select :presenter_ids, Spina::Admin::Conferences::Delegate.order(:last_name, :first_name), :id, :reversed_name_and_institution, {}, multiple: true, required: true + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :presenter_ids, Spina::Admin::Conferences::Delegate.order(:last_name, :first_name), :id, :reversed_name_and_institution do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label .horizontal-form-group{ class: dom_class(@presentation.attachments) } .horizontal-form-content diff --git a/config/locales/en.yml b/config/locales/en.yml index f30d1aac..d8e72f0b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -67,9 +67,6 @@ en: form_conference_details: delete_confirmation: "Are you sure you want to delete the conference %{name}?" - multiple_rooms_selection_instructions_html: - "Select multiple rooms by holding for a continuous selection, or, for a discontinous - selection, on Mac, or Ctrl on Windows and Linux" delegates: index: new: New delegate @@ -90,12 +87,6 @@ en: presentations: Presentations form_delegate_details: delete_confirmation: "Are you sure you want to delete the delegate %{delegate}?" - multiple_dietary_requirements_selection_instructions_html: - "Select multiple dietary requirements with and on Mac, or and - on Windows and Linux" - multiple_conferences_selection_instructions_html: - "Select multiple conferences with and on Mac, or and - on Windows and Linux" presenters: new: New presenter save: Save presenter @@ -123,9 +114,6 @@ en: presenters: Presenters form_presentation_details: delete_confirmation: "Are you sure you want to delete the presentation %{presentation}?" - multiple_presenters_selection_instructions_html: - "Select multiple presenters by holding for a continuous selection, or, for a discontinous - selection, on Mac, or Ctrl on Windows and Linux" presentation_types: index: new: New presentation type diff --git a/test/system/spina/admin/conferences/delegates_test.rb b/test/system/spina/admin/conferences/delegates_test.rb index 0dce80ca..a76704a0 100644 --- a/test/system/spina/admin/conferences/delegates_test.rb +++ b/test/system/spina/admin/conferences/delegates_test.rb @@ -36,8 +36,7 @@ class DelegatesTest < ApplicationSystemTestCase select @delegate.institution.name, from: 'delegate_institution_id' fill_in 'delegate_email_address', with: @delegate.email_address fill_in 'delegate_url', with: @delegate.url - @delegate - .conferences.each { |conference| select conference.name, from: 'delegate_conference_ids' } + @delegate.conferences.each { |conference| check conference.name, allow_label_click: true } Percy.snapshot page, name: 'Delegates form on create' click_on 'Save delegate' assert_text 'Delegate saved' @@ -58,8 +57,7 @@ class DelegatesTest < ApplicationSystemTestCase select @delegate.institution.name, from: 'delegate_institution_id' fill_in 'delegate_email_address', with: @delegate.email_address fill_in 'delegate_url', with: @delegate.url - @delegate - .conferences.each { |conference| select conference.name, from: 'delegate_conference_ids' } + @delegate.conferences.each { |conference| check conference.name, allow_label_click: true } click_on 'Save delegate' assert_text 'Delegate saved' Percy.snapshot page, name: 'Delegates index on update' diff --git a/test/system/spina/admin/conferences/presentations_test.rb b/test/system/spina/admin/conferences/presentations_test.rb index 4fa3c6b8..0f904157 100644 --- a/test/system/spina/admin/conferences/presentations_test.rb +++ b/test/system/spina/admin/conferences/presentations_test.rb @@ -37,9 +37,7 @@ class PresentationsTest < ApplicationSystemTestCase fill_in 'presentation_start_datetime', with: @presentation.start_datetime fill_in 'presentation_title', with: @presentation.title fill_in_rich_text_area 'presentation[abstract]', with: @presentation.abstract - @presentation.presenters.each do |presenter| - select presenter.reversed_name_and_institution, from: 'presentation_presenter_ids' - end + @presentation.presenters.each { |presenter| check presenter.reversed_name_and_institution, allow_label_click: true } within '.presentation_attachment' do click_link class: %w[button button-link icon] within '#structure_form_pane_0' do @@ -68,9 +66,7 @@ class PresentationsTest < ApplicationSystemTestCase fill_in 'presentation_start_datetime', with: @presentation.start_datetime fill_in 'presentation_title', with: @presentation.title fill_in_rich_text_area 'presentation[abstract]', with: @presentation.abstract - @presentation.presenters.each do |presenter| - select presenter.reversed_name_and_institution, from: 'presentation_presenter_ids' - end + @presentation.presenters.each { |presenter| check presenter.reversed_name_and_institution, allow_label_click: true } within '.presentation_attachment' do click_link class: %w[button button-link icon] find_link(href: '#structure_form_pane_2').click From e44759577c4daa93a1b22069c11cab8051b12aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Tue, 6 Apr 2021 21:23:26 +0100 Subject: [PATCH 13/21] Switch to page form --- .../conferences/_event_fields.html.haml | 24 ++-- .../_form_conference_details.html.haml | 41 ++++--- .../conferences/_form_parts.html.haml | 15 ++- .../_form_delegate_details.html.haml | 92 ++++++++------- .../_form_institution_details.html.haml | 47 ++++---- .../_form_presentation_type_details.html.haml | 25 ++--- .../_attachment_fields.html.haml | 8 +- .../_form_presentation_details.html.haml | 105 +++++++++--------- .../rooms/_form_room_details.html.haml | 27 +++-- .../sessions/_form_session_details.html.haml | 33 +++--- config/locales/en.yml | 1 - 11 files changed, 205 insertions(+), 213 deletions(-) diff --git a/app/views/spina/admin/conferences/conferences/_event_fields.html.haml b/app/views/spina/admin/conferences/conferences/_event_fields.html.haml index 86dc189f..2af621a8 100644 --- a/app/views/spina/admin/conferences/conferences/_event_fields.html.haml +++ b/app/views/spina/admin/conferences/conferences/_event_fields.html.haml @@ -1,27 +1,29 @@ .structure-form-pane{ class: ('active' if (local_assigns[:active] == true) || (f.index == 0)), id: "structure_form_pane_#{f.index}", data: { 'spina--admin--conferences--conference_events_form': { target: 'formPane' } } } .structure-form-part - .horizontal-form-label= Spina::Admin::Conferences::Event.human_attribute_name :name - .horizontal-form-content= f.text_field :name, placeholder: Spina::Admin::Conferences::Event.human_attribute_name(:name), required: true + .page-form-label= Spina::Admin::Conferences::Event.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Event.human_attribute_name(:name), required: true .structure-form-part - .horizontal-form-label= Spina::Admin::Conferences::Event.human_attribute_name :start_datetime - .horizontal-form-content= f.datetime_field :start_datetime, + .page-form-label= Spina::Admin::Conferences::Event.human_attribute_name :start_datetime + .page-form-control= f.datetime_field :start_datetime, placeholder: Spina::Admin::Conferences::Event.human_attribute_name(:start_datetime), required: true .structure-form-part - .horizontal-form-label= Spina::Admin::Conferences::Event.human_attribute_name :finish_datetime - .horizontal-form-content= f.datetime_field :finish_datetime, + .page-form-label= Spina::Admin::Conferences::Event.human_attribute_name :finish_datetime + .page-form-control= f.datetime_field :finish_datetime, placeholder: Spina::Admin::Conferences::Event.human_attribute_name(:finish_datetime), required: true .structure-form-part - .horizontal-form-label= Spina::Admin::Conferences::Event.human_attribute_name :location - .horizontal-form-content= f.text_field :location, placeholder: Spina::Admin::Conferences::Event.human_attribute_name(:location), - required: true + .page-form-label= Spina::Admin::Conferences::Event.human_attribute_name :location + .page-form-control= f.text_field :location, placeholder: Spina::Admin::Conferences::Event.human_attribute_name(:location), + required: true .structure-form-part - .horizontal-form-label= Spina::Admin::Conferences::Event.human_attribute_name :description - .horizontal-form-content= render 'spina/admin/shared/rich_text_field', f: f, field: :description + .page-form-label= Spina::Admin::Conferences::Event.human_attribute_name :description + .page-form-content + .page-form-rich-text + = render 'spina/admin/shared/rich_text_field', f: f, field: :description = f.hidden_field :id diff --git a/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml b/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml index 42f23418..59c20bc1 100644 --- a/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml @@ -1,29 +1,28 @@ #conference_details.tab-content.active - .well - .horizontal-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { config_value: '{ "admin_conferences_conference_institution_id": { "value": "id", "text": "name" }, "admin_conferences_conference_room_ids": { "trigger": "admin_conferences_conference_institution_id", "key": "rooms", "value": "id", "text": "name" } }', record_value: @institutions } } } - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :name - .horizontal-form-content= f.text_field :name, placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:name), required: true + .page-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { config_value: '{ "admin_conferences_conference_institution_id": { "value": "id", "text": "name" }, "admin_conferences_conference_room_ids": { "trigger": "admin_conferences_conference_institution_id", "key": "rooms", "value": "id", "text": "name" } }', record_value: @institutions } } } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:name), required: true, class: 'input-large' - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :start_date - .horizontal-form-content= f.date_field :start_date, value: (@conference.start_date.strftime("%Y-%m-%d") if @conference.start_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:start_date), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :start_date + .page-form-control= f.date_field :start_date, value: (@conference.start_date.strftime("%Y-%m-%d") if @conference.start_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:start_date), required: true - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :finish_date - .horizontal-form-content= f.date_field :finish_date, value: (@conference.finish_date.strftime("%Y-%m-%d") if @conference.finish_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:finish_date), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :finish_date + .page-form-control= f.date_field :finish_date, value: (@conference.finish_date.strftime("%Y-%m-%d") if @conference.finish_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:finish_date), required: true - .horizontal-form-group{ class: dom_class(@conference.events) } - .horizontal-form-content - .structure-form{ data: { controller: 'spina--admin--conferences--conference-events-form', 'spina--admin--conferences--conference_events_form': { active_class: 'active' } } } - .structure-form-menu - %label= Spina::Admin::Conferences::Conference.human_attribute_name :events - %ul= render partial: 'event_row', collection: f.object.events, as: :event - = link_to icon('plus'), @conference.new_record? ? new_admin_conferences_event_path : new_admin_conferences_conference_event_path(@conference, index: @conference.events.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--conference_events_form_target': 'addFormLink', disable_with: '' } + .page-form-group{ class: dom_class(@conference.events) } + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :events + .page-form-control + .structure-form{ data: { controller: 'spina--admin--conferences--conference-events-form', 'spina--admin--conferences--conference_events_form': { active_class: 'active' } } } + .structure-form-menu + %ul= render partial: 'event_row', collection: f.object.events, as: :event + = link_to icon('plus'), @conference.new_record? ? new_admin_conferences_event_path : new_admin_conferences_conference_event_path(@conference, index: @conference.events.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--conference_events_form_target': 'addFormLink', disable_with: '' } - .structure-form-content{ data: { action: 'conferenceEventFieldsAdded->spina--admin--conferences--conference-events-form#updateURL' } } - = f.fields_for :events do |event_fields| - = render 'event_fields', f: event_fields + .structure-form-content{ data: { action: 'conferenceEventFieldsAdded->spina--admin--conferences--conference-events-form#updateURL' } } + = f.fields_for :events do |event_fields| + = render 'event_fields', f: event_fields - unless @conference.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_conference_path(@conference), method: :delete, data: { confirm: t('.delete_confirmation', name: @conference.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/conferences/_form_parts.html.haml b/app/views/spina/admin/conferences/conferences/_form_parts.html.haml index c9051b65..8cd36d72 100644 --- a/app/views/spina/admin/conferences/conferences/_form_parts.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_parts.html.haml @@ -1,10 +1,9 @@ #parts.tab-content - .well - .horizontal-form - = f.fields_for :"#{@locale}_content", @parts do |ff| - = ff.hidden_field :type, value: ff.object.class.name - = ff.hidden_field :title - = ff.hidden_field :name + .page-form + = f.fields_for :"#{@locale}_content", @parts do |ff| + = ff.hidden_field :type, value: ff.object.class.name + = ff.hidden_field :title + = ff.hidden_field :name - .horizontal-form-group.page-part{ data: { name: ff.object.name } } - = render "spina/admin/parts/#{parts_partial_namespace(ff.object.class.name)}/form", f: ff + .page-form-group.page-part{ data: { name: ff.object.name } } + = render "spina/admin/parts/#{parts_partial_namespace(ff.object.class.name)}/form", f: ff diff --git a/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml b/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml index 993a4276..009c5bec 100644 --- a/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml +++ b/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml @@ -1,56 +1,54 @@ #delegate_details.tab-content.active - .well - .horizontal-form - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :first_name - .horizontal-form-content= f.text_field :first_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:first_name), required: true + .page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :name + .page-form-control + .input-group + = f.text_field :first_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:first_name), required: true, class: 'input-large' + = f.text_field :last_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:last_name), required: true, class: 'input-large' - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :last_name - .horizontal-form-content= f.text_field :last_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:last_name), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :institution + .page-form-control + .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :institution - .horizontal-form-content - .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address + .page-form-control= f.email_field :email_address, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:email_address), required: true - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address - .horizontal-form-content= f.email_field :email_address, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:email_address), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :url + .page-form-control= f.url_field :url, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:url) - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :url - .horizontal-form-content= f.url_field :url, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:url) + .page-form-group + .page-form-label + = Spina::Admin::Conferences::Delegate.human_attribute_name :dietary_requirements + .page-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :dietary_requirement_ids, Spina::Admin::Conferences::DietaryRequirement.all, :id, :name do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label - .horizontal-form-group - .horizontal-form-label - = Spina::Admin::Conferences::Delegate.human_attribute_name :dietary_requirements - .horizontal-form-content - .well{ style: 'margin: 0' } - .table-container - %table.table{ style: 'margin: 0' } - %tbody - = f.collection_check_boxes :dietary_requirement_ids, Spina::Admin::Conferences::DietaryRequirement.all, :id, :name do |builder| - %tr - %td{ style: "padding-left: 16px" } - .form-checkbox - = builder.check_box - = builder.label - - .horizontal-form-group - .horizontal-form-label - = Spina::Admin::Conferences::Delegate.human_attribute_name :conferences - .horizontal-form-content - .well{ style: 'margin: 0' } - .table-container - %table.table{ style: 'margin: 0' } - %tbody - = f.collection_check_boxes :conference_ids, Spina::Admin::Conferences::Conference.all, :id, :name, {} do |builder| - %tr - %td{ style: "padding-left: 16px" } - .form-checkbox - = builder.check_box - = builder.label + .page-form-group + .page-form-label + = Spina::Admin::Conferences::Delegate.human_attribute_name :conferences + .page-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :conference_ids, Spina::Admin::Conferences::Conference.all, :id, :name, {} do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label - unless @delegate.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_delegate_path(@delegate), method: :delete, data: { confirm: t('.delete_confirmation', delegate: @delegate.full_name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml b/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml index 4b1521f4..777a7510 100644 --- a/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml +++ b/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml @@ -1,31 +1,30 @@ #institution_details.tab-content.active - .well - .horizontal-form - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :name - .horizontal-form-content= f.text_field :name, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:name), required: true + .page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:name), required: true, class: 'input-large' - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :city - .horizontal-form-content= f.text_field :city, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:city), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :city + .page-form-content= f.text_field :city, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:city), required: true - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :logo - .horizontal-form-content{ data: { controller: 'image-form' } } - .page-form-media-picker - %div{ style: 'width: 100%' } - = link_to admin_media_picker_path(selected_ids: [f.object.logo_id], input: "media_picker_#{f.object.object_id}", mode: 'single'), remote: true, class: 'image', data: { target: 'image-form.image' } do - .page-form-media-picker-placeholder= t 'spina.images.choose_image' - %div{ id: "media_picker_#{f.object.object_id}" } - = f.hidden_field :logo_id, data: { target: 'image-form.imageId' } - = f.hidden_field :logo_signed_blob_id, value: f.object.logo&.file&.signed_id, data: {target: 'image-form.signedBlobId'} - = f.hidden_field :logo_filename, value: f.object.logo&.file&.filename, data: {target: 'image-form.filename'} - %div{ style: 'width: 200px; height: 150px; overflow: hidden' } - - if f.object.logo.present? - = image_tag main_app.url_for(f.object.logo.variant(resize: '400x300^', crop: '400x300+0+0')), width: 200, height: 150 + .page-form-group + .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :logo + .page-form-content{ data: { controller: 'image-form' } } + .page-form-media-picker + %div{ style: 'width: 100%' } + = link_to admin_media_picker_path(selected_ids: [f.object.logo_id], input: "media_picker_#{f.object.object_id}", mode: 'single'), remote: true, class: 'image', data: { target: 'image-form.image' } do + .page-form-media-picker-placeholder= t 'spina.images.choose_image' + %div{ id: "media_picker_#{f.object.object_id}" } + = f.hidden_field :logo_id, data: { target: 'image-form.imageId' } + = f.hidden_field :logo_signed_blob_id, value: f.object.logo&.file&.signed_id, data: {target: 'image-form.signedBlobId'} + = f.hidden_field :logo_filename, value: f.object.logo&.file&.filename, data: {target: 'image-form.filename'} + %div{ style: 'width: 200px; height: 150px; overflow: hidden' } + - if f.object.logo.present? + = image_tag main_app.url_for(f.object.logo.variant(resize: '400x300^', crop: '400x300+0+0')), width: 200, height: 150 - = button_tag type: :default, class: 'button button-small button-default', data: { action: 'image-form#remove' } do - %i.icon.icon-cross{ style: 'margin: 0; font-size: 10px' } + = button_tag type: :default, class: 'button button-small button-default', data: { action: 'image-form#remove' } do + %i.icon.icon-cross{ style: 'margin: 0; font-size: 10px' } - unless @institution.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_institution_path(@institution), method: :delete, data: { confirm: t('.delete_confirmation', institution: @institution.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml b/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml index ceb8d794..00b8b487 100644 --- a/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml +++ b/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml @@ -1,20 +1,17 @@ #presentation_type_details.tab-content.active - .well - .horizontal-form - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :conference - .horizontal-form-content - .select-dropdown= f.collection_select :conference_id, Spina::Admin::Conferences::Conference.order(:dates).reverse_order, :id, :name, {}, required: true, data: { action: 'spina--admin--conferences--select-options#updateFilteredData' } + .page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :conference + .page-form-control + .select-dropdown= f.collection_select :conference_id, Spina::Admin::Conferences::Conference.order(:dates).reverse_order, :id, :name, {}, required: true, data: { action: 'spina--admin--conferences--select-options#updateFilteredData' } - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :name - .horizontal-form-content= f.text_field :name, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:name), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:name), required: true, class: 'input-large' - .horizontal-form-group - .horizontal-form-label - = Spina::Admin::Conferences::PresentationType.human_attribute_name :duration - %small= t '.duration_instructions' - .horizontal-form-content= f.number_field :minutes, value: @presentation_type.minutes, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:duration), required: true, step: 5, min: 5 + .page-form-group + .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :duration + .page-form-control= f.number_field :minutes, value: @presentation_type.minutes, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:duration), required: true, step: 5, min: 5 - unless @presentation_type.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_presentation_type_path(@presentation_type), method: :delete, data: { confirm: t('.delete_confirmation', presentation_type: @presentation_type.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml b/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml index 39f76073..ab28be56 100644 --- a/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml +++ b/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml @@ -1,14 +1,14 @@ .structure-form-pane{ class: ('active' if (local_assigns[:active] == true) || (f.index == 0)), id: "structure_form_pane_#{f.index}", data: { 'spina--admin--conferences--presentation_attachments_form': { target: 'formPane' } } } .structure-form-part - .horizontal-form-label + .page-form-label = Spina::Admin::Conferences::PresentationAttachment.human_attribute_name :attachment_type - .horizontal-form-content + .page-form-control .select-dropdown = f.collection_select :attachment_type_id, Spina::Admin::Conferences::PresentationAttachmentType.all, :id, :name, {}, data: { action: 'spina--admin--conferences--presentation-attachments-form#updateType' } .structure-form-part - .horizontal-form-label + .page-form-label = Spina::Admin::Conferences::PresentationAttachment.human_attribute_name :attachment - .horizontal-form-content{ data: { controller: "attachment-picker" } } + .page-form-content{ data: { controller: "attachment-picker" } } .select-dropdown = f.collection_select :attachment_id, Spina::Attachment.sorted, :id, :name, { include_blank: t("spina.attachments.choose_attachment") } diff --git a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml index 7f1425fd..103912dc 100644 --- a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml +++ b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml @@ -1,56 +1,57 @@ #presentation_details.tab-content.active - .well - .horizontal-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - .horizontal-form-content - .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@presentation.conference.id unless @presentation.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility', 'spina--admin--conferences--select_options_target': 'select', text_key: 'name' } - - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :session - .horizontal-form-content - .input-group - .select-dropdown= select_tag :presentation_type_id, options_from_collection_for_select((@presentation.conference || Spina::Admin::Conferences::Conference.first).presentation_types, :id, :name, (@presentation.presentation_type.id unless @presentation.presentation_type.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types', text_key: 'name' } - .select-dropdown= f.collection_select :session_id, (@presentation.presentation_type || Spina::Admin::Conferences::Conference.first).sessions, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types:sessions', text_key: 'name' } - - .horizontal-form-group - .horizontal-form-label - = Spina::Admin::Conferences::Presentation.human_attribute_name :start_datetime - .horizontal-form-content= f.datetime_field :start_datetime, required: true - - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :title - .horizontal-form-content= f.text_field :title, placeholder: Spina::Admin::Conferences::Presentation.human_attribute_name(:title), required: true - - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :abstract - .horizontal-form-content= render 'spina/admin/shared/rich_text_field', f: f, field: :abstract - - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - .horizontal-form-content - .well{ style: 'margin: 0' } - .table-container - %table.table{ style: 'margin: 0' } - %tbody - = f.collection_check_boxes :presenter_ids, Spina::Admin::Conferences::Delegate.order(:last_name, :first_name), :id, :reversed_name_and_institution do |builder| - %tr - %td{ style: "padding-left: 16px" } - .form-checkbox - = builder.check_box - = builder.label - - .horizontal-form-group{ class: dom_class(@presentation.attachments) } - .horizontal-form-content - .structure-form{ data: { controller: 'spina--admin--conferences--presentation-attachments-form', 'spina--admin--conferences--presentation_attachments_form': { active_class: 'active' } } } - .structure-form-menu - %label= Spina::Admin::Conferences::Presentation.human_attribute_name :attachments - %ul= render partial: 'attachment_row', collection: f.object.attachments, as: :attachment - = link_to icon('plus'), @presentation.new_record? ? new_admin_conferences_presentation_attachment_path : new_admin_conferences_presentation_presentation_attachment_path(@presentation, index: @presentation.attachments.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--presentation_attachments_form_target': 'addFormLink', disable_with: '' } - - .structure-form-content{ data: { action: 'presentationAttachmentFieldsAdded->spina--admin--conferences--presentation-attachments-form#updateURL' } } - = f.fields_for :attachments do |attachment_fields| - = render 'attachment_fields', f: attachment_fields + .page-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :conference + .page-form-control + .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@presentation.conference.id unless @presentation.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility', 'spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :session + .page-form-control + .input-group + .select-dropdown= select_tag :presentation_type_id, options_from_collection_for_select((@presentation.conference || Spina::Admin::Conferences::Conference.first).presentation_types, :id, :name, (@presentation.presentation_type.id unless @presentation.presentation_type.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types', text_key: 'name' } + .select-dropdown= f.collection_select :session_id, (@presentation.presentation_type || Spina::Admin::Conferences::Conference.first).sessions, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types:sessions', text_key: 'name' } + + .page-form-group + .page-form-label + = Spina::Admin::Conferences::Presentation.human_attribute_name :start_datetime + .page-form-control= f.datetime_field :start_datetime, required: true + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :title + .page-form-control= f.text_field :title, placeholder: Spina::Admin::Conferences::Presentation.human_attribute_name(:title), required: true, class: 'input-large' + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :abstract + .page-form-content + .page-form-rich-text + = render 'spina/admin/shared/rich_text_field', f: f, field: :abstract + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters + .page-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :presenter_ids, Spina::Admin::Conferences::Delegate.order(:last_name, :first_name), :id, :reversed_name_and_institution do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label + + .page-form-group{ class: dom_class(@presentation.attachments) } + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :attachments + .page-form-control + .structure-form{ data: { controller: 'spina--admin--conferences--presentation-attachments-form', 'spina--admin--conferences--presentation_attachments_form': { active_class: 'active' } } } + .structure-form-menu + %ul= render partial: 'attachment_row', collection: f.object.attachments, as: :attachment + = link_to icon('plus'), @presentation.new_record? ? new_admin_conferences_presentation_attachment_path : new_admin_conferences_presentation_presentation_attachment_path(@presentation, index: @presentation.attachments.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--presentation_attachments_form_target': 'addFormLink', disable_with: '' } + + .structure-form-content{ data: { action: 'presentationAttachmentFieldsAdded->spina--admin--conferences--presentation-attachments-form#updateURL' } } + = f.fields_for :attachments do |attachment_fields| + = render 'attachment_fields', f: attachment_fields - unless @presentation.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_presentation_path(@presentation), method: :delete, data: { confirm: t('.delete_confirmation', presentation: @presentation.title) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml b/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml index a0b2e199..7703871b 100644 --- a/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml +++ b/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml @@ -1,18 +1,17 @@ #room_details.tab-content.active - .well - .horizontal-form - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Room.human_attribute_name :institution - .horizontal-form-content - .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true + .page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :institution + .page-form-control + .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Room.human_attribute_name :building - .horizontal-form-content= f.text_field :building, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:building), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :building + .page-form-control= f.text_field :building, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:building), required: true - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Room.human_attribute_name :number - .horizontal-form-content= f.text_field :number, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:number), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :number + .page-form-control= f.text_field :number, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:number), required: true - - unless @room.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_room_path(@room), method: :delete, data: { confirm: t('.delete_confirmation', room: @room.name) }, class: %w[button button-link button-danger] +- unless @room.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_room_path(@room), method: :delete, data: { confirm: t('.delete_confirmation', room: @room.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml b/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml index 31b23a2d..0c22021f 100644 --- a/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml +++ b/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml @@ -1,23 +1,22 @@ #session_details.tab-content.active - .well - .horizontal-form - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Session.human_attribute_name :name - .horizontal-form-content= f.text_field :name, placeholder: Spina::Admin::Conferences::Session.human_attribute_name(:name), required: true + .page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Session.human_attribute_name(:name), required: true - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type - .horizontal-form-content - .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } - .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@session.conference.id unless @session.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } - .select-dropdown= f.collection_select :presentation_type_id, @session.conference.present? ? @session.conference.presentation_types : Spina::Admin::Conferences::Conference.first.presentation_types, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'presentation_types' } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type + .page-form-control + .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } + .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@session.conference.id unless @session.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + .select-dropdown= f.collection_select :presentation_type_id, @session.conference.present? ? @session.conference.presentation_types : Spina::Admin::Conferences::Conference.first.presentation_types, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'presentation_types' } - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::Session.human_attribute_name :room - .horizontal-form-content - .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @institutions } } } - .select-dropdown= select_tag :institution_id, options_from_collection_for_select(Spina::Admin::Conferences::Institution.all, :id, :name, (@session.institution.id unless @session.institution.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } - .select-dropdown= f.collection_select :room_id, @session.institution.present? ? @session.institution.rooms : Spina::Admin::Conferences::Institution.first.rooms, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'rooms' } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :room + .page-form-control + .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @institutions } } } + .select-dropdown= select_tag :institution_id, options_from_collection_for_select(Spina::Admin::Conferences::Institution.all, :id, :name, (@session.institution.id unless @session.institution.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + .select-dropdown= f.collection_select :room_id, @session.institution.present? ? @session.institution.rooms : Spina::Admin::Conferences::Institution.first.rooms, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'rooms' } - unless @session.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_session_path(@session), method: :delete, data: { confirm: t('.delete_confirmation', session: @session.name) }, class: %w[button button-link button-danger] diff --git a/config/locales/en.yml b/config/locales/en.yml index d8e72f0b..084bdc73 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -135,7 +135,6 @@ en: form_presentation_type_details: delete_confirmation: "Are you sure you want to delete the presentation type %{presentation_type}?" - duration_instructions: Enter in minutes dietary_requirements: index: new: New dietary requirement From a46d544c1849e1b0a61d999a4897b067e9e82398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Tue, 23 Mar 2021 17:54:52 +0000 Subject: [PATCH 14/21] Update horizontal forms --- .../_form_dietary_requirement_details.html.haml | 2 +- .../conferences/presentation_attachment_types/_form.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml b/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml index bdf977c8..356d383b 100644 --- a/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml +++ b/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml @@ -1,5 +1,5 @@ #dietary_requirement_details.tab-content.active - .well + %div{ style: 'margin-top: 40px' } .horizontal-form .horizontal-form-group .horizontal-form-label= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name diff --git a/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml b/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml index a009e39b..3fd104d2 100644 --- a/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml +++ b/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml @@ -13,7 +13,7 @@ = link_to t('spina.cancel'), admin_conferences_presentation_attachment_types_path, class: 'button', style: 'margin-right: 0' - .well + %div{ style: 'margin-top: 40px' } .horizontal-form .horizontal-form-group .horizontal-form-label= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name From 4a319a929f288e53133cf3de41e59090b9776d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Sun, 4 Apr 2021 02:22:37 +0100 Subject: [PATCH 15/21] Refactor to use new partials --- .../conferences/conferences/_form.html.haml | 8 +- .../_form_conference_details.html.haml | 45 ++++--- .../conferences/_form_delegates.html.haml | 1 - .../conferences/_form_parts.html.haml | 15 ++- .../_form_presentation_types.html.haml | 1 - .../conferences/_form_presentations.html.haml | 1 - .../conferences/_form_rooms.html.haml | 1 - .../conferences/delegates/_form.html.haml | 5 +- .../delegates/_form_conferences.html.haml | 1 - .../_form_delegate_details.html.haml | 95 ++++++++------- .../delegates/_form_presentations.html.haml | 1 - .../dietary_requirements/_form.html.haml | 4 +- .../_form_delegates.html.haml | 1 - ...form_dietary_requirement_details.html.haml | 15 ++- .../conferences/institutions/_form.html.haml | 5 +- .../institutions/_form_delegates.html.haml | 1 - .../_form_institution_details.html.haml | 51 ++++---- .../institutions/_form_rooms.html.haml | 1 - .../presentation_types/_form.html.haml | 5 +- .../_form_presentation_type_details.html.haml | 27 ++--- .../_form_presentations.html.haml | 1 - .../_form_sessions.html.haml | 1 - .../conferences/presentations/_form.html.haml | 4 +- .../_form_presentation_details.html.haml | 113 +++++++++--------- .../presentations/_form_presenters.html.haml | 1 - .../admin/conferences/rooms/_form.html.haml | 4 +- .../rooms/_form_presentations.html.haml | 1 - .../rooms/_form_room_details.html.haml | 23 ++-- .../conferences/sessions/_form.html.haml | 4 +- .../sessions/_form_presentations.html.haml | 1 - .../sessions/_form_session_details.html.haml | 37 +++--- 31 files changed, 229 insertions(+), 245 deletions(-) delete mode 100644 app/views/spina/admin/conferences/conferences/_form_delegates.html.haml delete mode 100644 app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml delete mode 100644 app/views/spina/admin/conferences/conferences/_form_presentations.html.haml delete mode 100644 app/views/spina/admin/conferences/conferences/_form_rooms.html.haml delete mode 100644 app/views/spina/admin/conferences/delegates/_form_conferences.html.haml delete mode 100644 app/views/spina/admin/conferences/delegates/_form_presentations.html.haml delete mode 100644 app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml delete mode 100644 app/views/spina/admin/conferences/institutions/_form_delegates.html.haml delete mode 100644 app/views/spina/admin/conferences/institutions/_form_rooms.html.haml delete mode 100644 app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml delete mode 100644 app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml delete mode 100644 app/views/spina/admin/conferences/presentations/_form_presenters.html.haml delete mode 100644 app/views/spina/admin/conferences/rooms/_form_presentations.html.haml delete mode 100644 app/views/spina/admin/conferences/sessions/_form_presentations.html.haml diff --git a/app/views/spina/admin/conferences/conferences/_form.html.haml b/app/views/spina/admin/conferences/conferences/_form.html.haml index 1df36f04..6065e205 100644 --- a/app/views/spina/admin/conferences/conferences/_form.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form.html.haml @@ -19,5 +19,9 @@ %li{ class: ('active' if i == 0) } = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #conference_details.tab-content.active= render 'form_conference_details', f: f + #parts.tab-content= render 'form_parts', f: f + #rooms.tab-content= render partial: 'rooms', object: @conference.rooms + #presentation_types.tab-content= render partial: 'presentation_types', object: @conference.presentation_types + #delegates.tab-content= render partial: 'delegates', object: @conference.delegates + #presentations.tab-content= render partial: 'presentations', object: @conference.presentations diff --git a/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml b/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml index 59c20bc1..72af739f 100644 --- a/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml @@ -1,28 +1,27 @@ -#conference_details.tab-content.active - .page-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { config_value: '{ "admin_conferences_conference_institution_id": { "value": "id", "text": "name" }, "admin_conferences_conference_room_ids": { "trigger": "admin_conferences_conference_institution_id", "key": "rooms", "value": "id", "text": "name" } }', record_value: @institutions } } } - .page-form-group - .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :name - .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:name), required: true, class: 'input-large' +.page-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { config_value: '{ "admin_conferences_conference_institution_id": { "value": "id", "text": "name" }, "admin_conferences_conference_room_ids": { "trigger": "admin_conferences_conference_institution_id", "key": "rooms", "value": "id", "text": "name" } }', record_value: @institutions } } } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:name), required: true, class: 'input-large' - .page-form-group - .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :start_date - .page-form-control= f.date_field :start_date, value: (@conference.start_date.strftime("%Y-%m-%d") if @conference.start_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:start_date), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :start_date + .page-form-control= f.date_field :start_date, value: (@conference.start_date.strftime("%Y-%m-%d") if @conference.start_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:start_date), required: true - .page-form-group - .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :finish_date - .page-form-control= f.date_field :finish_date, value: (@conference.finish_date.strftime("%Y-%m-%d") if @conference.finish_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:finish_date), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :finish_date + .page-form-control= f.date_field :finish_date, value: (@conference.finish_date.strftime("%Y-%m-%d") if @conference.finish_date.present?), placeholder: Spina::Admin::Conferences::Conference.human_attribute_name(:finish_date), required: true - .page-form-group{ class: dom_class(@conference.events) } - .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :events - .page-form-control - .structure-form{ data: { controller: 'spina--admin--conferences--conference-events-form', 'spina--admin--conferences--conference_events_form': { active_class: 'active' } } } - .structure-form-menu - %ul= render partial: 'event_row', collection: f.object.events, as: :event - = link_to icon('plus'), @conference.new_record? ? new_admin_conferences_event_path : new_admin_conferences_conference_event_path(@conference, index: @conference.events.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--conference_events_form_target': 'addFormLink', disable_with: '' } + .page-form-group{ class: dom_class(@conference.events) } + .page-form-label= Spina::Admin::Conferences::Conference.human_attribute_name :events + .page-form-control + .structure-form{ data: { controller: 'spina--admin--conferences--conference-events-form', 'spina--admin--conferences--conference_events_form': { active_class: 'active' } } } + .structure-form-menu + %ul= render partial: 'event_row', collection: f.object.events, as: :event + = link_to icon('plus'), @conference.new_record? ? new_admin_conferences_event_path : new_admin_conferences_conference_event_path(@conference, index: @conference.events.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--conference_events_form_target': 'addFormLink', disable_with: '' } - .structure-form-content{ data: { action: 'conferenceEventFieldsAdded->spina--admin--conferences--conference-events-form#updateURL' } } - = f.fields_for :events do |event_fields| - = render 'event_fields', f: event_fields + .structure-form-content{ data: { action: 'conferenceEventFieldsAdded->spina--admin--conferences--conference-events-form#updateURL' } } + = f.fields_for :events do |event_fields| + = render 'event_fields', f: event_fields - - unless @conference.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_conference_path(@conference), method: :delete, data: { confirm: t('.delete_confirmation', name: @conference.name) }, class: %w[button button-link button-danger] +- unless @conference.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_conference_path(@conference), method: :delete, data: { confirm: t('.delete_confirmation', name: @conference.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml b/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml deleted file mode 100644 index f8c2fcbb..00000000 --- a/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml +++ /dev/null @@ -1 +0,0 @@ -#delegates.tab-content= render partial: 'delegates', object: @conference.delegates diff --git a/app/views/spina/admin/conferences/conferences/_form_parts.html.haml b/app/views/spina/admin/conferences/conferences/_form_parts.html.haml index 8cd36d72..9aa8b0c2 100644 --- a/app/views/spina/admin/conferences/conferences/_form_parts.html.haml +++ b/app/views/spina/admin/conferences/conferences/_form_parts.html.haml @@ -1,9 +1,8 @@ -#parts.tab-content - .page-form - = f.fields_for :"#{@locale}_content", @parts do |ff| - = ff.hidden_field :type, value: ff.object.class.name - = ff.hidden_field :title - = ff.hidden_field :name +.page-form + = f.fields_for :"#{@locale}_content", @parts do |ff| + = ff.hidden_field :type, value: ff.object.class.name + = ff.hidden_field :title + = ff.hidden_field :name - .page-form-group.page-part{ data: { name: ff.object.name } } - = render "spina/admin/parts/#{parts_partial_namespace(ff.object.class.name)}/form", f: ff + .page-form-group.page-part{ data: { name: ff.object.name } } + = render "spina/admin/parts/#{parts_partial_namespace(ff.object.class.name)}/form", f: ff diff --git a/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml b/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml deleted file mode 100644 index 3afbf014..00000000 --- a/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml +++ /dev/null @@ -1 +0,0 @@ -#presentation_types.tab-content= render partial: 'presentation_types', object: @conference.presentation_types diff --git a/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml b/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml deleted file mode 100644 index 184e6279..00000000 --- a/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml +++ /dev/null @@ -1 +0,0 @@ -#presentations.tab-content= render partial: 'presentations', object: @conference.presentations diff --git a/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml b/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml deleted file mode 100644 index 6f27fae0..00000000 --- a/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml +++ /dev/null @@ -1 +0,0 @@ -#rooms.tab-content= render partial: 'rooms', object: @conference.rooms diff --git a/app/views/spina/admin/conferences/delegates/_form.html.haml b/app/views/spina/admin/conferences/delegates/_form.html.haml index 670dd875..97077c3a 100644 --- a/app/views/spina/admin/conferences/delegates/_form.html.haml +++ b/app/views/spina/admin/conferences/delegates/_form.html.haml @@ -19,5 +19,6 @@ %li{ class: ('active' if i == 0) } = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #delegate_details.tab-content.active= render 'form_delegate_details', f: f + #conferences.tab-content= render partial: 'conferences', object: @delegate.conferences + #presentations.tab-content= render partial: 'presentations', object: @delegate.presentations diff --git a/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml b/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml deleted file mode 100644 index 67c5444a..00000000 --- a/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml +++ /dev/null @@ -1 +0,0 @@ -#conferences.tab-content= render partial: 'conferences', object: @delegate.conferences diff --git a/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml b/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml index 009c5bec..6f8d4369 100644 --- a/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml +++ b/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml @@ -1,54 +1,53 @@ -#delegate_details.tab-content.active - .page-form - .page-form-group - .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :name - .page-form-control - .input-group - = f.text_field :first_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:first_name), required: true, class: 'input-large' - = f.text_field :last_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:last_name), required: true, class: 'input-large' +.page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :name + .page-form-control + .input-group + = f.text_field :first_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:first_name), required: true, class: 'input-large' + = f.text_field :last_name, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:last_name), required: true, class: 'input-large' - .page-form-group - .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :institution - .page-form-control - .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :institution + .page-form-control + .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true - .page-form-group - .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address - .page-form-control= f.email_field :email_address, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:email_address), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :email_address + .page-form-control= f.email_field :email_address, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:email_address), required: true - .page-form-group - .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :url - .page-form-control= f.url_field :url, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:url) + .page-form-group + .page-form-label= Spina::Admin::Conferences::Delegate.human_attribute_name :url + .page-form-control= f.url_field :url, placeholder: Spina::Admin::Conferences::Delegate.human_attribute_name(:url) - .page-form-group - .page-form-label - = Spina::Admin::Conferences::Delegate.human_attribute_name :dietary_requirements - .page-form-content - .well{ style: 'margin: 0' } - .table-container - %table.table{ style: 'margin: 0' } - %tbody - = f.collection_check_boxes :dietary_requirement_ids, Spina::Admin::Conferences::DietaryRequirement.all, :id, :name do |builder| - %tr - %td{ style: "padding-left: 16px" } - .form-checkbox - = builder.check_box - = builder.label + .page-form-group + .page-form-label + = Spina::Admin::Conferences::Delegate.human_attribute_name :dietary_requirements + .page-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :dietary_requirement_ids, Spina::Admin::Conferences::DietaryRequirement.all, :id, :name do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label - .page-form-group - .page-form-label - = Spina::Admin::Conferences::Delegate.human_attribute_name :conferences - .page-form-content - .well{ style: 'margin: 0' } - .table-container - %table.table{ style: 'margin: 0' } - %tbody - = f.collection_check_boxes :conference_ids, Spina::Admin::Conferences::Conference.all, :id, :name, {} do |builder| - %tr - %td{ style: "padding-left: 16px" } - .form-checkbox - = builder.check_box - = builder.label + .page-form-group + .page-form-label + = Spina::Admin::Conferences::Delegate.human_attribute_name :conferences + .page-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :conference_ids, Spina::Admin::Conferences::Conference.all, :id, :name, {} do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label - - unless @delegate.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_delegate_path(@delegate), method: :delete, data: { confirm: t('.delete_confirmation', delegate: @delegate.full_name) }, class: %w[button button-link button-danger] +- unless @delegate.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_delegate_path(@delegate), method: :delete, data: { confirm: t('.delete_confirmation', delegate: @delegate.full_name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml b/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml deleted file mode 100644 index 34958dba..00000000 --- a/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml +++ /dev/null @@ -1 +0,0 @@ -#presentations.tab-content= render partial: 'presentations', object: @delegate.presentations diff --git a/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml b/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml index 83f0e361..0eddbab7 100644 --- a/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml +++ b/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml @@ -19,5 +19,5 @@ %li{ class: ('active' if i == 0) } = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #dietary_requirement_details.tab-content.active= render 'form_dietary_requirement_details', f: f + #delegates.tab-content= render partial: 'delegates', object: @dietary_requirement.delegates diff --git a/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml b/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml deleted file mode 100644 index a71bd7ec..00000000 --- a/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml +++ /dev/null @@ -1 +0,0 @@ -#delegates.tab-content= render partial: 'delegates', object: @dietary_requirement.delegates diff --git a/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml b/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml index 356d383b..1a833ae0 100644 --- a/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml +++ b/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml @@ -1,9 +1,8 @@ -#dietary_requirement_details.tab-content.active - %div{ style: 'margin-top: 40px' } - .horizontal-form - .horizontal-form-group - .horizontal-form-label= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name - .horizontal-form-content= f.text_field :name, placeholder: Spina::Admin::Conferences::DietaryRequirement.human_attribute_name(:name), required: true +%div{ style: 'margin-top: 40px' } + .horizontal-form + .horizontal-form-group + .horizontal-form-label= Spina::Admin::Conferences::DietaryRequirement.human_attribute_name :name + .horizontal-form-content= f.text_field :name, placeholder: Spina::Admin::Conferences::DietaryRequirement.human_attribute_name(:name), required: true - - unless @dietary_requirement.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_dietary_requirement_path(@dietary_requirement), method: :delete, data: { confirm: t('.delete_confirmation', dietary_requirement: @dietary_requirement.name) }, class: %w[button button-link button-danger] +- unless @dietary_requirement.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_dietary_requirement_path(@dietary_requirement), method: :delete, data: { confirm: t('.delete_confirmation', dietary_requirement: @dietary_requirement.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/institutions/_form.html.haml b/app/views/spina/admin/conferences/institutions/_form.html.haml index f1647518..8e8afb73 100644 --- a/app/views/spina/admin/conferences/institutions/_form.html.haml +++ b/app/views/spina/admin/conferences/institutions/_form.html.haml @@ -19,5 +19,6 @@ %li{ class: ('active' if i == 0) } = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #institution_details.tab-content.active= render 'form_institution_details', f: f + #rooms.tab-content= render partial: 'rooms', object: @institution.rooms + #delegates.tab-content= render partial: 'delegates', object: @institution.delegates diff --git a/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml b/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml deleted file mode 100644 index 6fdde5f4..00000000 --- a/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml +++ /dev/null @@ -1 +0,0 @@ -#delegates.tab-content= render partial: 'delegates', object: @institution.delegates diff --git a/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml b/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml index 777a7510..075cff48 100644 --- a/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml +++ b/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml @@ -1,30 +1,29 @@ -#institution_details.tab-content.active - .page-form - .page-form-group - .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :name - .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:name), required: true, class: 'input-large' +.page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:name), required: true, class: 'input-large' - .page-form-group - .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :city - .page-form-content= f.text_field :city, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:city), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :city + .page-form-control= f.text_field :city, placeholder: Spina::Admin::Conferences::Institution.human_attribute_name(:city), required: true - .page-form-group - .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :logo - .page-form-content{ data: { controller: 'image-form' } } - .page-form-media-picker - %div{ style: 'width: 100%' } - = link_to admin_media_picker_path(selected_ids: [f.object.logo_id], input: "media_picker_#{f.object.object_id}", mode: 'single'), remote: true, class: 'image', data: { target: 'image-form.image' } do - .page-form-media-picker-placeholder= t 'spina.images.choose_image' - %div{ id: "media_picker_#{f.object.object_id}" } - = f.hidden_field :logo_id, data: { target: 'image-form.imageId' } - = f.hidden_field :logo_signed_blob_id, value: f.object.logo&.file&.signed_id, data: {target: 'image-form.signedBlobId'} - = f.hidden_field :logo_filename, value: f.object.logo&.file&.filename, data: {target: 'image-form.filename'} - %div{ style: 'width: 200px; height: 150px; overflow: hidden' } - - if f.object.logo.present? - = image_tag main_app.url_for(f.object.logo.variant(resize: '400x300^', crop: '400x300+0+0')), width: 200, height: 150 + .page-form-group + .page-form-label= Spina::Admin::Conferences::Institution.human_attribute_name :logo + .page-form-content{ data: { controller: 'image-form' } } + .page-form-media-picker + %div{ style: 'width: 100%' } + = link_to admin_media_picker_path(selected_ids: [f.object.logo_id], input: "media_picker_#{f.object.object_id}", mode: 'single'), remote: true, class: 'image', data: { target: 'image-form.image' } do + .page-form-media-picker-placeholder= t 'spina.images.choose_image' + %div{ id: "media_picker_#{f.object.object_id}" } + = f.hidden_field :logo_id, data: { target: 'image-form.imageId' } + = f.hidden_field :logo_signed_blob_id, value: f.object.logo&.file&.signed_id, data: {target: 'image-form.signedBlobId'} + = f.hidden_field :logo_filename, value: f.object.logo&.file&.filename, data: {target: 'image-form.filename'} + %div{ style: 'width: 200px; height: 150px; overflow: hidden' } + - if f.object.logo.present? + = image_tag main_app.url_for(f.object.logo.variant(resize: '400x300^', crop: '400x300+0+0')), width: 200, height: 150 - = button_tag type: :default, class: 'button button-small button-default', data: { action: 'image-form#remove' } do - %i.icon.icon-cross{ style: 'margin: 0; font-size: 10px' } + = button_tag type: :default, class: 'button button-small button-default', data: { action: 'image-form#remove' } do + %i.icon.icon-cross{ style: 'margin: 0; font-size: 10px' } - - unless @institution.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_institution_path(@institution), method: :delete, data: { confirm: t('.delete_confirmation', institution: @institution.name) }, class: %w[button button-link button-danger] +- unless @institution.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_institution_path(@institution), method: :delete, data: { confirm: t('.delete_confirmation', institution: @institution.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml b/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml deleted file mode 100644 index a6acba69..00000000 --- a/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml +++ /dev/null @@ -1 +0,0 @@ -#rooms.tab-content= render partial: 'rooms', object: @institution.rooms diff --git a/app/views/spina/admin/conferences/presentation_types/_form.html.haml b/app/views/spina/admin/conferences/presentation_types/_form.html.haml index 937bf2b5..26dde001 100644 --- a/app/views/spina/admin/conferences/presentation_types/_form.html.haml +++ b/app/views/spina/admin/conferences/presentation_types/_form.html.haml @@ -19,5 +19,6 @@ %li{ class: ('active' if i == 0) } = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #presentation_type_details.tab-content.active= render 'form_presentation_type_details', f: f + #sessions.tab-content= render partial: 'sessions', object: @presentation_type.sessions + #presentations.tab-content= render partial: 'presentations', object: @presentation_type.presentations diff --git a/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml b/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml index 00b8b487..0305738f 100644 --- a/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml +++ b/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml @@ -1,17 +1,16 @@ -#presentation_type_details.tab-content.active - .page-form - .page-form-group - .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :conference - .page-form-control - .select-dropdown= f.collection_select :conference_id, Spina::Admin::Conferences::Conference.order(:dates).reverse_order, :id, :name, {}, required: true, data: { action: 'spina--admin--conferences--select-options#updateFilteredData' } +.page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :conference + .page-form-control + .select-dropdown= f.collection_select :conference_id, Spina::Admin::Conferences::Conference.order(:dates).reverse_order, :id, :name, {}, required: true, data: { action: 'spina--admin--conferences--select-options#updateFilteredData' } - .page-form-group - .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :name - .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:name), required: true, class: 'input-large' + .page-form-group + .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:name), required: true, class: 'input-large' - .page-form-group - .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :duration - .page-form-control= f.number_field :minutes, value: @presentation_type.minutes, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:duration), required: true, step: 5, min: 5 + .page-form-group + .page-form-label= Spina::Admin::Conferences::PresentationType.human_attribute_name :duration + .page-form-control= f.number_field :minutes, value: @presentation_type.minutes, placeholder: Spina::Admin::Conferences::PresentationType.human_attribute_name(:duration), required: true, step: 5, min: 5 - - unless @presentation_type.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_presentation_type_path(@presentation_type), method: :delete, data: { confirm: t('.delete_confirmation', presentation_type: @presentation_type.name) }, class: %w[button button-link button-danger] +- unless @presentation_type.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_presentation_type_path(@presentation_type), method: :delete, data: { confirm: t('.delete_confirmation', presentation_type: @presentation_type.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml b/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml deleted file mode 100644 index 719e73f5..00000000 --- a/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml +++ /dev/null @@ -1 +0,0 @@ -#presentations.tab-content= render partial: 'presentations', object: @presentation_type.presentations \ No newline at end of file diff --git a/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml b/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml deleted file mode 100644 index 75ee621a..00000000 --- a/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml +++ /dev/null @@ -1 +0,0 @@ -#sessions.tab-content= render partial: 'sessions', object: @presentation_type.sessions diff --git a/app/views/spina/admin/conferences/presentations/_form.html.haml b/app/views/spina/admin/conferences/presentations/_form.html.haml index 42cdc23d..a6fd71a8 100644 --- a/app/views/spina/admin/conferences/presentations/_form.html.haml +++ b/app/views/spina/admin/conferences/presentations/_form.html.haml @@ -19,5 +19,5 @@ %li{ class: ('active' if i == 0) } = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #presentation_details.tab-content.active= render 'form_presentation_details', f: f + #presenters.tab-content= render partial: 'delegates', object: @presentation.presenters diff --git a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml index 103912dc..0376f893 100644 --- a/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml +++ b/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml @@ -1,57 +1,56 @@ -#presentation_details.tab-content.active - .page-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } - .page-form-group - .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :conference - .page-form-control - .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@presentation.conference.id unless @presentation.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility', 'spina--admin--conferences--select_options_target': 'select', text_key: 'name' } - - .page-form-group - .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :session - .page-form-control - .input-group - .select-dropdown= select_tag :presentation_type_id, options_from_collection_for_select((@presentation.conference || Spina::Admin::Conferences::Conference.first).presentation_types, :id, :name, (@presentation.presentation_type.id unless @presentation.presentation_type.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types', text_key: 'name' } - .select-dropdown= f.collection_select :session_id, (@presentation.presentation_type || Spina::Admin::Conferences::Conference.first).sessions, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types:sessions', text_key: 'name' } - - .page-form-group - .page-form-label - = Spina::Admin::Conferences::Presentation.human_attribute_name :start_datetime - .page-form-control= f.datetime_field :start_datetime, required: true - - .page-form-group - .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :title - .page-form-control= f.text_field :title, placeholder: Spina::Admin::Conferences::Presentation.human_attribute_name(:title), required: true, class: 'input-large' - - .page-form-group - .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :abstract - .page-form-content - .page-form-rich-text - = render 'spina/admin/shared/rich_text_field', f: f, field: :abstract - - .page-form-group - .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters - .page-form-content - .well{ style: 'margin: 0' } - .table-container - %table.table{ style: 'margin: 0' } - %tbody - = f.collection_check_boxes :presenter_ids, Spina::Admin::Conferences::Delegate.order(:last_name, :first_name), :id, :reversed_name_and_institution do |builder| - %tr - %td{ style: "padding-left: 16px" } - .form-checkbox - = builder.check_box - = builder.label - - .page-form-group{ class: dom_class(@presentation.attachments) } - .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :attachments - .page-form-control - .structure-form{ data: { controller: 'spina--admin--conferences--presentation-attachments-form', 'spina--admin--conferences--presentation_attachments_form': { active_class: 'active' } } } - .structure-form-menu - %ul= render partial: 'attachment_row', collection: f.object.attachments, as: :attachment - = link_to icon('plus'), @presentation.new_record? ? new_admin_conferences_presentation_attachment_path : new_admin_conferences_presentation_presentation_attachment_path(@presentation, index: @presentation.attachments.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--presentation_attachments_form_target': 'addFormLink', disable_with: '' } - - .structure-form-content{ data: { action: 'presentationAttachmentFieldsAdded->spina--admin--conferences--presentation-attachments-form#updateURL' } } - = f.fields_for :attachments do |attachment_fields| - = render 'attachment_fields', f: attachment_fields - - - unless @presentation.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_presentation_path(@presentation), method: :delete, data: { confirm: t('.delete_confirmation', presentation: @presentation.title) }, class: %w[button button-link button-danger] +.page-form{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :conference + .page-form-control + .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@presentation.conference.id unless @presentation.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility', 'spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :session + .page-form-control + .input-group + .select-dropdown= select_tag :presentation_type_id, options_from_collection_for_select((@presentation.conference || Spina::Admin::Conferences::Conference.first).presentation_types, :id, :name, (@presentation.presentation_type.id unless @presentation.presentation_type.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types', text_key: 'name' } + .select-dropdown= f.collection_select :session_id, (@presentation.presentation_type || Spina::Admin::Conferences::Conference.first).sessions, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', key_path: 'presentation_types:sessions', text_key: 'name' } + + .page-form-group + .page-form-label + = Spina::Admin::Conferences::Presentation.human_attribute_name :start_datetime + .page-form-control= f.datetime_field :start_datetime, required: true + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :title + .page-form-control= f.text_field :title, placeholder: Spina::Admin::Conferences::Presentation.human_attribute_name(:title), required: true, class: 'input-large' + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :abstract + .page-form-content + .page-form-rich-text + = render 'spina/admin/shared/rich_text_field', f: f, field: :abstract + + .page-form-group + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters + .page-form-content + .well{ style: 'margin: 0' } + .table-container + %table.table{ style: 'margin: 0' } + %tbody + = f.collection_check_boxes :presenter_ids, Spina::Admin::Conferences::Delegate.order(:last_name, :first_name), :id, :reversed_name_and_institution do |builder| + %tr + %td{ style: "padding-left: 16px" } + .form-checkbox + = builder.check_box + = builder.label + + .page-form-group{ class: dom_class(@presentation.attachments) } + .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :attachments + .page-form-control + .structure-form{ data: { controller: 'spina--admin--conferences--presentation-attachments-form', 'spina--admin--conferences--presentation_attachments_form': { active_class: 'active' } } } + .structure-form-menu + %ul= render partial: 'attachment_row', collection: f.object.attachments, as: :attachment + = link_to icon('plus'), @presentation.new_record? ? new_admin_conferences_presentation_attachment_path : new_admin_conferences_presentation_presentation_attachment_path(@presentation, index: @presentation.attachments.size), remote: true, class: %w[button button-link icon], data: { 'spina--admin--conferences--presentation_attachments_form_target': 'addFormLink', disable_with: '' } + + .structure-form-content{ data: { action: 'presentationAttachmentFieldsAdded->spina--admin--conferences--presentation-attachments-form#updateURL' } } + = f.fields_for :attachments do |attachment_fields| + = render 'attachment_fields', f: attachment_fields + +- unless @presentation.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_presentation_path(@presentation), method: :delete, data: { confirm: t('.delete_confirmation', presentation: @presentation.title) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml b/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml deleted file mode 100644 index 02f54f32..00000000 --- a/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml +++ /dev/null @@ -1 +0,0 @@ -#presenters.tab-content= render partial: 'delegates', object: @presentation.presenters diff --git a/app/views/spina/admin/conferences/rooms/_form.html.haml b/app/views/spina/admin/conferences/rooms/_form.html.haml index 84533b25..8d1f20b9 100644 --- a/app/views/spina/admin/conferences/rooms/_form.html.haml +++ b/app/views/spina/admin/conferences/rooms/_form.html.haml @@ -19,5 +19,5 @@ %li{ class: ('active'if i == 0)} = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #room_details.tab-content.active= render 'form_room_details', f: f + #presentations.tab-content= render partial: 'presentations', object: @room.presentations diff --git a/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml b/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml deleted file mode 100644 index 0f191d6e..00000000 --- a/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml +++ /dev/null @@ -1 +0,0 @@ -#presentations.tab-content= render partial: 'presentations', object: @room.presentations diff --git a/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml b/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml index 7703871b..0d87e6cb 100644 --- a/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml +++ b/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml @@ -1,17 +1,16 @@ -#room_details.tab-content.active - .page-form - .page-form-group - .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :institution - .page-form-control - .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true +.page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :institution + .page-form-control + .select-dropdown= f.collection_select :institution_id, Spina::Admin::Conferences::Institution.all, :id, :name, {}, required: true - .page-form-group - .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :building - .page-form-control= f.text_field :building, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:building), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :building + .page-form-control= f.text_field :building, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:building), required: true - .page-form-group - .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :number - .page-form-control= f.text_field :number, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:number), required: true + .page-form-group + .page-form-label= Spina::Admin::Conferences::Room.human_attribute_name :number + .page-form-control= f.text_field :number, placeholder: Spina::Admin::Conferences::Room.human_attribute_name(:number), required: true - unless @room.new_record? .pull-right= link_to t('spina.permanently_delete'), admin_conferences_room_path(@room), method: :delete, data: { confirm: t('.delete_confirmation', room: @room.name) }, class: %w[button button-link button-danger] diff --git a/app/views/spina/admin/conferences/sessions/_form.html.haml b/app/views/spina/admin/conferences/sessions/_form.html.haml index 7603a30c..5b093ced 100644 --- a/app/views/spina/admin/conferences/sessions/_form.html.haml +++ b/app/views/spina/admin/conferences/sessions/_form.html.haml @@ -19,5 +19,5 @@ %li{ class: ('active'if i == 0)} = link_to t(".#{tab}"), "##{tab}" - - @tabs.each do |tab| - = render "form_#{tab}", f: f + #session_details.tab-content.active= render 'form_session_details', f: f + #presentations.tab-content= render partial: 'presentations', object: @session.presentations diff --git a/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml b/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml deleted file mode 100644 index d8a6cef0..00000000 --- a/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml +++ /dev/null @@ -1 +0,0 @@ -#presentations.tab-content= render partial: 'presentations', object: @session.presentations diff --git a/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml b/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml index 0c22021f..7b526e7a 100644 --- a/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml +++ b/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml @@ -1,22 +1,21 @@ -#session_details.tab-content.active - .page-form - .page-form-group - .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :name - .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Session.human_attribute_name(:name), required: true +.page-form + .page-form-group + .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :name + .page-form-control= f.text_field :name, placeholder: Spina::Admin::Conferences::Session.human_attribute_name(:name), required: true - .page-form-group - .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type - .page-form-control - .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } - .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@session.conference.id unless @session.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } - .select-dropdown= f.collection_select :presentation_type_id, @session.conference.present? ? @session.conference.presentation_types : Spina::Admin::Conferences::Conference.first.presentation_types, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'presentation_types' } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :presentation_type + .page-form-control + .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @conferences } } } + .select-dropdown= select_tag :conference_id, options_from_collection_for_select(Spina::Admin::Conferences::Conference.all, :id, :name, (@session.conference.id unless @session.conference.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + .select-dropdown= f.collection_select :presentation_type_id, @session.conference.present? ? @session.conference.presentation_types : Spina::Admin::Conferences::Conference.first.presentation_types, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'presentation_types' } - .page-form-group - .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :room - .page-form-control - .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @institutions } } } - .select-dropdown= select_tag :institution_id, options_from_collection_for_select(Spina::Admin::Conferences::Institution.all, :id, :name, (@session.institution.id unless @session.institution.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } - .select-dropdown= f.collection_select :room_id, @session.institution.present? ? @session.institution.rooms : Spina::Admin::Conferences::Institution.first.rooms, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'rooms' } + .page-form-group + .page-form-label= Spina::Admin::Conferences::Session.human_attribute_name :room + .page-form-control + .input-group{ data: { controller: 'spina--admin--conferences--select-options', 'spina--admin--conferences--select_options': { record_value: @institutions } } } + .select-dropdown= select_tag :institution_id, options_from_collection_for_select(Spina::Admin::Conferences::Institution.all, :id, :name, (@session.institution.id unless @session.institution.blank?)), include_blank: true, required: true, data: { action: 'spina--admin--conferences--select-options#setVisibility','spina--admin--conferences--select_options_target': 'select', text_key: 'name' } + .select-dropdown= f.collection_select :room_id, @session.institution.present? ? @session.institution.rooms : Spina::Admin::Conferences::Institution.first.rooms, :id, :name, { include_blank: true }, required: true, data: {'spina--admin--conferences--select_options_target': 'select', text_key: 'name', key_path: 'rooms' } - - unless @session.new_record? - .pull-right= link_to t('spina.permanently_delete'), admin_conferences_session_path(@session), method: :delete, data: { confirm: t('.delete_confirmation', session: @session.name) }, class: %w[button button-link button-danger] +- unless @session.new_record? + .pull-right= link_to t('spina.permanently_delete'), admin_conferences_session_path(@session), method: :delete, data: { confirm: t('.delete_confirmation', session: @session.name) }, class: %w[button button-link button-danger] From 25d3744a6ee0eb689c1e080d60ff27e04f16c0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Tue, 23 Mar 2021 18:04:37 +0000 Subject: [PATCH 16/21] Add Rake task --- lib/tasks/spina/admin/conferences_tasks.rake | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/tasks/spina/admin/conferences_tasks.rake b/lib/tasks/spina/admin/conferences_tasks.rake index 7a1afbe7..0d885951 100644 --- a/lib/tasks/spina/admin/conferences_tasks.rake +++ b/lib/tasks/spina/admin/conferences_tasks.rake @@ -1,4 +1,14 @@ # frozen_string_literal: true -namespace :spina_admin_conferences do +namespace :spina do + Rake::Task[:convert_layout_parts_to_json].clear if Rake::Task.task_defined?('spina:convert_layout_parts_to_json') + Rake::Task[:convert_page_parts_to_json].clear if Rake::Task.task_defined?('spina:convert_page_parts_to_json') + + desc 'Convert table-based partables to JSON-based parts' + task convert_parts_to_json: [:environment, :'spina_admin_conferences:install:migrations'] do + puts "If the upgrade migrations were missing, they should now have been copied to your migrations path.\n" \ + 'If you have custom partables, you must modify the upgrade migration before running it: ' \ + "for more information, see the documentation in the migration.\n" \ + 'Once the migration is ready, run `rails db:migrate`.' + end end From 3305bcb05ca5d140c47634fe35d39c3cd5038d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Wed, 7 Apr 2021 01:10:08 +0100 Subject: [PATCH 17/21] Test for redirects --- test/system/spina/admin/conferences/conferences_test.rb | 3 +++ test/system/spina/admin/conferences/delegates_test.rb | 3 +++ .../spina/admin/conferences/dietary_requirements_test.rb | 3 +++ test/system/spina/admin/conferences/institutions_test.rb | 3 +++ .../admin/conferences/presentation_attachment_types_test.rb | 3 +++ test/system/spina/admin/conferences/presentation_types_test.rb | 3 +++ test/system/spina/admin/conferences/presentations_test.rb | 3 +++ test/system/spina/admin/conferences/rooms_test.rb | 3 +++ test/system/spina/admin/conferences/sessions_test.rb | 3 +++ 9 files changed, 27 insertions(+) diff --git a/test/system/spina/admin/conferences/conferences_test.rb b/test/system/spina/admin/conferences/conferences_test.rb index 6227a4d6..29f56d5a 100644 --- a/test/system/spina/admin/conferences/conferences_test.rb +++ b/test/system/spina/admin/conferences/conferences_test.rb @@ -86,6 +86,7 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas first('.media-picker-image').click end click_on 'Save conference' + assert_current_path admin_conferences_conferences_path assert_text 'Conference saved' Percy.snapshot page, name: 'Conferences index on create' end @@ -154,6 +155,7 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas first('.media-picker-image').click end click_on 'Save conference' + assert_current_path admin_conferences_conferences_path assert_text 'Conference saved' Percy.snapshot page, name: 'Conferences index on update' end @@ -170,6 +172,7 @@ class ConferencesTest < ApplicationSystemTestCase # rubocop:disable Metrics/Clas click_on 'Permanently delete' Percy.snapshot page, name: 'Conferences delete dialog' end + assert_current_path admin_conferences_conferences_path assert_text 'Conference deleted' assert_no_selector "tr[data-conference-id=\"#{@empty_conference.id}\"]" Percy.snapshot page, name: 'Conferences index on delete' diff --git a/test/system/spina/admin/conferences/delegates_test.rb b/test/system/spina/admin/conferences/delegates_test.rb index a76704a0..05d84d29 100644 --- a/test/system/spina/admin/conferences/delegates_test.rb +++ b/test/system/spina/admin/conferences/delegates_test.rb @@ -39,6 +39,7 @@ class DelegatesTest < ApplicationSystemTestCase @delegate.conferences.each { |conference| check conference.name, allow_label_click: true } Percy.snapshot page, name: 'Delegates form on create' click_on 'Save delegate' + assert_current_path admin_conferences_delegates_path assert_text 'Delegate saved' Percy.snapshot page, name: 'Delegates index on create' end @@ -59,6 +60,7 @@ class DelegatesTest < ApplicationSystemTestCase fill_in 'delegate_url', with: @delegate.url @delegate.conferences.each { |conference| check conference.name, allow_label_click: true } click_on 'Save delegate' + assert_current_path admin_conferences_delegates_path assert_text 'Delegate saved' Percy.snapshot page, name: 'Delegates index on update' end @@ -75,6 +77,7 @@ class DelegatesTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Delegates delete dialog' end + assert_current_path admin_conferences_delegates_path assert_text 'Delegate deleted' assert_no_selector "tr[data-delegate-id=\"#{@delegate.id}\"]" Percy.snapshot page, name: 'Delegates index on delete' diff --git a/test/system/spina/admin/conferences/dietary_requirements_test.rb b/test/system/spina/admin/conferences/dietary_requirements_test.rb index ed118380..3e0640bf 100644 --- a/test/system/spina/admin/conferences/dietary_requirements_test.rb +++ b/test/system/spina/admin/conferences/dietary_requirements_test.rb @@ -34,6 +34,7 @@ class DietaryRequirementsTest < ApplicationSystemTestCase fill_in 'dietary_requirement_name', with: @dietary_requirement.name Percy.snapshot page, name: 'Dietary requirements form on create' click_on 'Save dietary requirement' + assert_current_path admin_conferences_dietary_requirements_path assert_text 'Dietary requirement saved' Percy.snapshot page, name: 'Dietary requirements index on create' end @@ -49,6 +50,7 @@ class DietaryRequirementsTest < ApplicationSystemTestCase Percy.snapshot page, name: 'Dietary requirements form on update' fill_in 'dietary_requirement_name', with: @dietary_requirement.name click_on 'Save dietary requirement' + assert_current_path admin_conferences_dietary_requirements_path assert_text 'Dietary requirement saved' Percy.snapshot page, name: 'Dietary requirements index on update' end @@ -65,6 +67,7 @@ class DietaryRequirementsTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Dietary requirements delete dialog' end + assert_current_path admin_conferences_dietary_requirements_path assert_text 'Dietary requirement deleted' assert_no_selector "tr[data-dietary-requirement-id=\"#{@dietary_requirement.id}\"]" Percy.snapshot page, name: 'Dietary requirements index on delete' diff --git a/test/system/spina/admin/conferences/institutions_test.rb b/test/system/spina/admin/conferences/institutions_test.rb index b51f3d8d..d165f0fc 100644 --- a/test/system/spina/admin/conferences/institutions_test.rb +++ b/test/system/spina/admin/conferences/institutions_test.rb @@ -40,6 +40,7 @@ class InstitutionsTest < ApplicationSystemTestCase end Percy.snapshot page, name: 'Institutions form on create' click_on 'Save institution' + assert_current_path admin_conferences_institutions_path assert_text 'Institution saved' Percy.snapshot page, name: 'Institutions index on create' end @@ -60,6 +61,7 @@ class InstitutionsTest < ApplicationSystemTestCase first('.media-picker-image').click end click_on 'Save institution' + assert_current_path admin_conferences_institutions_path assert_text 'Institution saved' Percy.snapshot page, name: 'Institutions index on update' end @@ -76,6 +78,7 @@ class InstitutionsTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Institutions delete dialog' end + assert_current_path admin_conferences_institutions_path assert_text 'Institution deleted' assert_no_selector "tr[data-institution-id=\"#{@empty_institution.id}\"]" Percy.snapshot page, name: 'Institutions index on delete' diff --git a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb index 1b2892ab..30cdc23b 100644 --- a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb +++ b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb @@ -34,6 +34,7 @@ class PresentationAttachmentTypesTest < ApplicationSystemTestCase fill_in 'presentation_attachment_type_name', with: @presentation_attachment_type.name Percy.snapshot page, name: 'Presentation attachment types form on create' click_on 'Save presentation attachment type' + assert_current_path admin_conferences_presentation_attachment_types_path assert_text 'Presentation attachment type saved' Percy.snapshot page, name: 'Presentation attachment types index on create' end @@ -49,6 +50,7 @@ class PresentationAttachmentTypesTest < ApplicationSystemTestCase Percy.snapshot page, name: 'Presentation attachment types form on update' fill_in 'presentation_attachment_type_name', with: @presentation_attachment_type.name click_on 'Save presentation attachment type' + assert_current_path admin_conferences_presentation_attachment_types_path assert_text 'Presentation attachment type saved' Percy.snapshot page, name: 'Presentation attachment types index on update' end @@ -65,6 +67,7 @@ class PresentationAttachmentTypesTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Presentation attachment types delete dialog' end + assert_current_path admin_conferences_presentation_attachment_types_path assert_text 'Presentation attachment type deleted' assert_no_selector "tr[data-dietary-requirement-id=\"#{@presentation_attachment_type.id}\"]" Percy.snapshot page, name: 'Presentation attachment types index on delete' diff --git a/test/system/spina/admin/conferences/presentation_types_test.rb b/test/system/spina/admin/conferences/presentation_types_test.rb index 7698551f..bf6781c6 100644 --- a/test/system/spina/admin/conferences/presentation_types_test.rb +++ b/test/system/spina/admin/conferences/presentation_types_test.rb @@ -37,6 +37,7 @@ class PresentationTypesTest < ApplicationSystemTestCase fill_in 'presentation_type_minutes', with: @presentation_type.minutes Percy.snapshot page, name: 'Presentation types form on create' click_on 'Save presentation type' + assert_current_path admin_conferences_presentation_types_path assert_text 'Presentation type saved' Percy.snapshot page, name: 'Presentation types index on create' end @@ -54,6 +55,7 @@ class PresentationTypesTest < ApplicationSystemTestCase fill_in 'presentation_type_name', with: @presentation_type.name fill_in 'presentation_type_minutes', with: @presentation_type.minutes click_on 'Save presentation type' + assert_current_path admin_conferences_presentation_types_path assert_text 'Presentation type saved' Percy.snapshot page, name: 'Presentation types index on update' end @@ -70,6 +72,7 @@ class PresentationTypesTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Presentation types delete dialog' end + assert_current_path admin_conferences_presentation_types_path assert_text 'Presentation type deleted' assert_no_selector "tr[data-presentation-type-id=\"#{@empty_presentation_type.id}\"]" Percy.snapshot page, name: 'Presentation types index on delete' diff --git a/test/system/spina/admin/conferences/presentations_test.rb b/test/system/spina/admin/conferences/presentations_test.rb index 0f904157..9c71937f 100644 --- a/test/system/spina/admin/conferences/presentations_test.rb +++ b/test/system/spina/admin/conferences/presentations_test.rb @@ -47,6 +47,7 @@ class PresentationsTest < ApplicationSystemTestCase end Percy.snapshot page, name: 'Presentations form on create' click_on 'Save presentation' + assert_current_path admin_conferences_presentations_path assert_text 'Presentation saved' Percy.snapshot page, name: 'Presentations index on create' end @@ -76,6 +77,7 @@ class PresentationsTest < ApplicationSystemTestCase end end click_on 'Save presentation' + assert_current_path admin_conferences_presentations_path assert_text 'Presentation saved' Percy.snapshot page, name: 'Presentations index on update' end @@ -92,6 +94,7 @@ class PresentationsTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Presentations delete dialog' end + assert_current_path admin_conferences_presentations_path assert_text 'Presentation deleted' assert_no_selector "tr[data-presentation-id=\"#{@presentation.id}\"]" Percy.snapshot page, name: 'Presentations index on delete' diff --git a/test/system/spina/admin/conferences/rooms_test.rb b/test/system/spina/admin/conferences/rooms_test.rb index fd2440c5..c1ed8261 100644 --- a/test/system/spina/admin/conferences/rooms_test.rb +++ b/test/system/spina/admin/conferences/rooms_test.rb @@ -37,6 +37,7 @@ class RoomsTest < ApplicationSystemTestCase fill_in 'room_number', with: @room.number Percy.snapshot page, name: 'Rooms form on create' click_on 'Save room' + assert_current_path admin_conferences_rooms_path assert_text 'Room saved' Percy.snapshot page, name: 'Rooms index on create' end @@ -54,6 +55,7 @@ class RoomsTest < ApplicationSystemTestCase fill_in 'room_building', with: @room.building fill_in 'room_number', with: @room.number click_on 'Save room' + assert_current_path admin_conferences_rooms_path assert_text 'Room saved' Percy.snapshot page, name: 'Rooms index on update' end @@ -70,6 +72,7 @@ class RoomsTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Rooms delete dialog' end + assert_current_path admin_conferences_rooms_path assert_text 'Room deleted' assert_no_selector "tr[data-room-id=\"#{@empty_room.id}\"]" Percy.snapshot page, name: 'Rooms index on delete' diff --git a/test/system/spina/admin/conferences/sessions_test.rb b/test/system/spina/admin/conferences/sessions_test.rb index 041df5b7..3d38c7ee 100644 --- a/test/system/spina/admin/conferences/sessions_test.rb +++ b/test/system/spina/admin/conferences/sessions_test.rb @@ -39,6 +39,7 @@ class SessionsTest < ApplicationSystemTestCase select @session.room.name, from: 'session_room_id' Percy.snapshot page, name: 'Sessions form on create' click_on 'Save session' + assert_current_path admin_conferences_sessions_path assert_text 'Session saved' Percy.snapshot page, name: 'Sessions index on create' end @@ -58,6 +59,7 @@ class SessionsTest < ApplicationSystemTestCase select @session.institution.name, from: 'institution_id' select @session.room.name, from: 'session_room_id' click_on 'Save session' + assert_current_path admin_conferences_sessions_path assert_text 'Session saved' Percy.snapshot page, name: 'Sessions index on update' end @@ -74,6 +76,7 @@ class SessionsTest < ApplicationSystemTestCase click_on 'Permanently delete' Percy.snapshot page, name: 'Sessions delete dialog' end + assert_current_path admin_conferences_sessions_path assert_text 'Session deleted' assert_no_selector "tr[data-session-id=\"#{@empty_session.id}\"]" Percy.snapshot page, name: 'Sessions index on delete' From 177f631d03a3d951453ce0f5e0b24bc1fdfe17d5 Mon Sep 17 00:00:00 2001 From: codefactor-io Date: Wed, 7 Apr 2021 01:17:17 +0000 Subject: [PATCH 18/21] [CodeFactor] Apply fixes --- .../conferences/conferences_controller.rb | 20 +++++++++---------- ...0210315164411_convert_partables_to_json.rb | 1 - lib/tasks/spina/admin/conferences_tasks.rake | 2 +- .../config/initializers/themes/default.rb | 3 +-- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/app/controllers/spina/admin/conferences/conferences_controller.rb b/app/controllers/spina/admin/conferences/conferences_controller.rb index 39404d56..6d7ff307 100644 --- a/app/controllers/spina/admin/conferences/conferences_controller.rb +++ b/app/controllers/spina/admin/conferences/conferences_controller.rb @@ -8,18 +8,18 @@ module Conferences class ConferencesController < ApplicationController PARTS_PARAMS = [ :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, - images_attributes: %i[filename signed_blob_id image_id alt], - content_attributes: [ - :name, :title, - parts_attributes: [ - :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, - images_attributes: %i[filename signed_blob_id image_id alt] - ] - ] + { images_attributes: %i[filename signed_blob_id image_id alt], + content_attributes: [ + :name, :title, + { parts_attributes: [ + :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, + { images_attributes: %i[filename signed_blob_id image_id alt] } + ] } + ] } ].freeze CONTENT_PARAMS = Spina.config.locales.inject({}) { |params, locale| params.merge("#{locale}_content_attributes": [*PARTS_PARAMS]) } - PARAMS = [:start_date, :finish_date, :name, **CONTENT_PARAMS, - events_attributes: %i[id name start_datetime finish_datetime description location]].freeze + PARAMS = [:start_date, :finish_date, :name, { **CONTENT_PARAMS, + events_attributes: %i[id name start_datetime finish_datetime description location] }].freeze PARTS = %w[text submission_url submission_email_address submission_date submission_text gallery sponsors].freeze before_action :set_conference, only: %i[edit update destroy] diff --git a/db/migrate/20210315164411_convert_partables_to_json.rb b/db/migrate/20210315164411_convert_partables_to_json.rb index 33d7db7d..0ddc6fd2 100644 --- a/db/migrate/20210315164411_convert_partables_to_json.rb +++ b/db/migrate/20210315164411_convert_partables_to_json.rb @@ -336,7 +336,6 @@ def convert_to_partable! module Admin module Conferences - class DatePart < ApplicationRecord def convert_to_json! Spina::Parts::Admin::Conferences::Date.new(content: content) diff --git a/lib/tasks/spina/admin/conferences_tasks.rake b/lib/tasks/spina/admin/conferences_tasks.rake index 0d885951..05f91783 100644 --- a/lib/tasks/spina/admin/conferences_tasks.rake +++ b/lib/tasks/spina/admin/conferences_tasks.rake @@ -5,7 +5,7 @@ namespace :spina do Rake::Task[:convert_page_parts_to_json].clear if Rake::Task.task_defined?('spina:convert_page_parts_to_json') desc 'Convert table-based partables to JSON-based parts' - task convert_parts_to_json: [:environment, :'spina_admin_conferences:install:migrations'] do + task convert_parts_to_json: %i[environment spina_admin_conferences:install:migrations] do puts "If the upgrade migrations were missing, they should now have been copied to your migrations path.\n" \ 'If you have custom partables, you must modify the upgrade migration before running it: ' \ "for more information, see the documentation in the migration.\n" \ diff --git a/test/dummy/config/initializers/themes/default.rb b/test/dummy/config/initializers/themes/default.rb index 915ce0e7..b46867b9 100644 --- a/test/dummy/config/initializers/themes/default.rb +++ b/test/dummy/config/initializers/themes/default.rb @@ -120,8 +120,7 @@ name: 'submission_text', title: 'Submission text', part_type: 'Spina::Parts::Line' - } -] + }] theme.view_templates = [{ name: 'homepage', From 16d0ab95ab547138bc1e90ccd2b7618d5a4ca385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Wed, 7 Apr 2021 15:06:21 +0100 Subject: [PATCH 19/21] Fix linter errors --- .rubocop.yml | 3 + ...utes_to_spina_conferences_presentations.rb | 2 +- ...ibutes_to_spina_conferences_conferences.rb | 2 +- ...0210315164411_convert_partables_to_json.rb | 67 +++++++++---------- .../conferences_controller_test.rb | 30 +++------ ...json_attributes_to_spina_accounts.spina.rb | 2 + ...dd_json_attributes_to_spina_pages.spina.rb | 2 + ...01208_add_slug_to_spina_resources.spina.rb | 2 + test/fixtures/spina/pages.yml | 6 +- .../parts/admin/conferences/time_test.rb | 4 +- .../presentation_attachment_types_test.rb | 3 +- 11 files changed, 59 insertions(+), 64 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 4fc82a3c..6ff90feb 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -9,6 +9,9 @@ AllCops: Style/CommandLiteral: EnforcedStyle: mixed +Style/HashAsLastArrayItem: + EnforcedStyle: no_braces + Layout/LineLength: Max: 140 AutoCorrect: true diff --git a/db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb b/db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb index ef80bc14..58ea1f6a 100644 --- a/db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb +++ b/db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class AddJsonAttributesToSpinaConferencesPresentations < ActiveRecord::Migration[6.1] +class AddJsonAttributesToSpinaConferencesPresentations < ActiveRecord::Migration[6.1] # :nodoc: def change add_column :spina_conferences_presentations, :json_attributes, :jsonb end diff --git a/db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb b/db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb index 070c9994..4938ea2c 100644 --- a/db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb +++ b/db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class AddJsonAttributesToSpinaConferencesConferences < ActiveRecord::Migration[6.1] +class AddJsonAttributesToSpinaConferencesConferences < ActiveRecord::Migration[6.1] # :nodoc: def change add_column :spina_conferences_conferences, :json_attributes, :jsonb end diff --git a/db/migrate/20210315164411_convert_partables_to_json.rb b/db/migrate/20210315164411_convert_partables_to_json.rb index 0ddc6fd2..522bc9f7 100644 --- a/db/migrate/20210315164411_convert_partables_to_json.rb +++ b/db/migrate/20210315164411_convert_partables_to_json.rb @@ -1,9 +1,5 @@ # frozen_string_literal: true -# This migration converts table-based partables from Spina v1 to the new JSON-based parts in Spina v2. -# If you have custom partables you must modify this migration to ensure the conversion of your partables is handled appropriately -# by implementing convert_to_json! for your partables. - # Reregistering parts necessary due to deserialization from JSON, where class instances from registration used Spina::Part.all.delete_if { |part| Spina::Parts::Admin::Conferences.constants.include? :"#{part.name.demodulize}" } Spina::Part.register(Spina::Parts::Admin::Conferences::Date) @@ -11,8 +7,11 @@ Spina::Part.register(Spina::Parts::Admin::Conferences::Time) Spina::Part.register(Spina::Parts::Admin::Conferences::Url) +# This migration converts table-based partables from Spina v1 to the new JSON-based parts in Spina v2. +# If you have custom partables you must modify this migration to ensure the conversion of your partables is handled appropriately +# by implementing convert_to_json! for your partables. class ConvertPartablesToJson < ActiveRecord::Migration[6.1] - def up + def up # rubocop:disable Metrics/MethodLength, Metrics/AbcSize announce 'converting partables to JSON parts' Spina.config.locales.each do |locale| I18n.with_locale(locale) do @@ -38,7 +37,7 @@ def up end end - def down + def down # rubocop:disable Metrics/MethodLength, Metrics/AbcSize announce 'converting JSON parts to partables' Spina.config.locales.each do |locale| I18n.with_locale(locale) do @@ -65,7 +64,7 @@ def down end end -module Spina +module Spina # :nodoc: all class ImageCollectionsImage < Spina::ApplicationRecord belongs_to :image belongs_to :image_collection @@ -248,7 +247,7 @@ def convert_to_json! end end - module Parts + module Parts # :nodoc: all class Attachment < Base def convert_to_partable! Spina::Attachment.find(attachment_id) @@ -374,40 +373,34 @@ def convert_to_json! end end - class Conference < ApplicationRecord - has_many :parts, as: :pageable - - def convert_parts_to_json! - parts.reject { |part| part.partable.nil? } - .collect(&:convert_to_json!) - .compact - .then { |parts| send(:"#{I18n.locale}_content").union(parts) } - .then { |parts| update("#{I18n.locale}_content": parts) } - end + module Pageable + extend ActiveSupport::Concern - def convert_json_to_parts! - update(parts: send(:"#{I18n.locale}_content").collect(&:convert_to_partable!) - .compact - .collect { |partable| Part.new(partable: partable) }) + included do + has_many :parts, as: :pageable + + def convert_parts_to_json! + parts.reject { |part| part.partable.nil? } + .collect(&:convert_to_json!) + .compact + .then { |parts| send(:"#{I18n.locale}_content").union(parts) } + .then { |parts| update("#{I18n.locale}_content": parts) } + end + + def convert_json_to_parts! + update(parts: send(:"#{I18n.locale}_content").collect(&:convert_to_partable!) + .compact + .collect { |partable| Part.new(partable: partable) }) + end end end - class Presentation < ApplicationRecord - has_many :parts, as: :pageable - - def convert_parts_to_json! - parts.reject { |part| part.partable.nil? } - .collect(&:convert_to_json!) - .compact - .then { |parts| send(:"#{I18n.locale}_content").union(parts) } - .then { |parts| update("#{I18n.locale}_content": parts) } - end + class Conference < ApplicationRecord + include Pageable + end - def convert_json_to_parts! - update(parts: send(:"#{I18n.locale}_content").collect(&:convert_to_partable!) - .compact - .collect { |partable| Part.new(partable: partable) }) - end + class Presentation < ApplicationRecord + include Pageable end end end diff --git a/test/controllers/spina/admin/conferences/conferences_controller_test.rb b/test/controllers/spina/admin/conferences/conferences_controller_test.rb index ca870ed1..48f3c5fb 100644 --- a/test/controllers/spina/admin/conferences/conferences_controller_test.rb +++ b/test/controllers/spina/admin/conferences/conferences_controller_test.rb @@ -196,15 +196,11 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:finish_date] = @conference.finish_date attributes[:name] = @conference.name attributes[:'en-GB_content_attributes'] = [ - { title: 'Sponsors', name: 'sponsors', type: 'Spina::Parts::Repeater', content_attributes: - [ - { title: 'Sponsors', name: 'sponsors', parts_attributes: - [ - { title: 'Name', name: 'name', content: 'Another sponsor', type: 'Spina::Parts::Line' } - ] - } - ] - } + { title: 'Sponsors', name: 'sponsors', type: 'Spina::Parts::Repeater', content_attributes: [ + { title: 'Sponsors', name: 'sponsors', parts_attributes: [ + { title: 'Name', name: 'name', content: 'Another sponsor', type: 'Spina::Parts::Line' } + ] } + ] } ] assert_changes -> { @conference.reload.content(:sponsors).first.content('name') }, from: 'Some sponsor', to: 'Another sponsor' do patch admin_conferences_conference_url(@conference), params: { conference: attributes }, as: :turbo_stream @@ -217,16 +213,12 @@ class ConferencesControllerTest < ActionDispatch::IntegrationTest # rubocop:disa attributes[:finish_date] = @conference.finish_date attributes[:name] = @conference.name attributes[:'en-GB_content_attributes'] = [ - { title: 'Sponsors', name: 'sponsors', type: 'Spina::Parts::Repeater', content_attributes: - [ - { title: 'Sponsors', name: 'sponsors', parts_attributes: - [ - { title: 'Logo', name: 'logo', type: 'Spina::Parts::Image', image_id: @rovinj_image.id, filename: 'logo.jpeg', - signed_blob_id: '', alt: 'Logo' } - ] - } - ] - } + { title: 'Sponsors', name: 'sponsors', type: 'Spina::Parts::Repeater', content_attributes: [ + { title: 'Sponsors', name: 'sponsors', parts_attributes: [ + { title: 'Logo', name: 'logo', type: 'Spina::Parts::Image', image_id: @rovinj_image.id, filename: 'logo.jpeg', + signed_blob_id: '', alt: 'Logo' } + ] } + ] } ] assert_changes -> { @conference.reload.content(:sponsors).first.content(:logo).spina_image }, from: @logo, to: @rovinj_image do diff --git a/test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb b/test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb index 2210b670..d53453b7 100644 --- a/test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb +++ b/test/dummy/db/migrate/20210321001206_add_json_attributes_to_spina_accounts.spina.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This migration comes from spina (originally 13) class AddJsonAttributesToSpinaAccounts < ActiveRecord::Migration[5.2] def change diff --git a/test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb b/test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb index 7b8abfbe..51b0df3f 100644 --- a/test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb +++ b/test/dummy/db/migrate/20210321001207_add_json_attributes_to_spina_pages.spina.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This migration comes from spina (originally 14) class AddJsonAttributesToSpinaPages < ActiveRecord::Migration[5.2] def change diff --git a/test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb b/test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb index 0c935399..b31ed359 100644 --- a/test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb +++ b/test/dummy/db/migrate/20210321001208_add_slug_to_spina_resources.spina.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This migration comes from spina (originally 15) class AddSlugToSpinaResources < ActiveRecord::Migration[5.2] def change diff --git a/test/fixtures/spina/pages.yml b/test/fixtures/spina/pages.yml index 20740472..8e8d5146 100644 --- a/test/fixtures/spina/pages.yml +++ b/test/fixtures/spina/pages.yml @@ -46,7 +46,7 @@ about: - name: text title: Text type: Spina::Parts::Text - content: + content:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis @@ -56,7 +56,7 @@ about: - name: contact title: Contact type: Spina::Parts::Text - content: + content:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis @@ -113,7 +113,7 @@ about: - name: contact title: Contact type: Spina::Parts::Text - content: + content:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis a ex ac leo interdum dictum eu sed risus. Curabitur eros mauris, malesuada in turpis in, rutrum laoreet velit. Quisque vel consequat arcu, vel hendrerit nisl. Vivamus eu turpis luctus, facilisis quam ut, aliquet ipsum. Etiam accumsan tellus turpis, vel placerat felis diff --git a/test/models/spina/parts/admin/conferences/time_test.rb b/test/models/spina/parts/admin/conferences/time_test.rb index 9b0330b0..3fa4bf7a 100644 --- a/test/models/spina/parts/admin/conferences/time_test.rb +++ b/test/models/spina/parts/admin/conferences/time_test.rb @@ -8,8 +8,8 @@ module Admin module Conferences class TimeTest < ActiveSupport::TestCase setup do - @time_part = Time.new(content: 10.years.from_now) - @new_time_part = Time.new + @time_part = Time.new(content: 10.years.from_now) # rubocop:disable Rails/TimeZone + @new_time_part = Time.new # rubocop:disable Rails/TimeZone end test 'time has content' do diff --git a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb index 30cdc23b..2089139d 100644 --- a/test/system/spina/admin/conferences/presentation_attachment_types_test.rb +++ b/test/system/spina/admin/conferences/presentation_attachment_types_test.rb @@ -63,7 +63,8 @@ class PresentationAttachmentTypesTest < ApplicationSystemTestCase assert_selector '.breadcrumbs' do assert_text @presentation_attachment_type.name end - accept_confirm "Are you sure you want to delete the presentation attachment type #{@presentation_attachment_type.name}?" do + accept_confirm "Are you sure you want to delete the presentation attachment type #{@presentation_attachment_type.name}" \ + '?' do click_on 'Permanently delete' Percy.snapshot page, name: 'Presentation attachment types delete dialog' end From d44b85451c63eaaaca718e3fa7a5f64e55312941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Malc=CC=8Cic=CC=81?= Date: Wed, 7 Apr 2021 15:06:34 +0100 Subject: [PATCH 20/21] Fix incorrect method call --- db/migrate/20210315164411_convert_partables_to_json.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20210315164411_convert_partables_to_json.rb b/db/migrate/20210315164411_convert_partables_to_json.rb index 522bc9f7..0d467051 100644 --- a/db/migrate/20210315164411_convert_partables_to_json.rb +++ b/db/migrate/20210315164411_convert_partables_to_json.rb @@ -262,7 +262,7 @@ def convert_to_partable! class ImageCollection < Base def convert_to_partable! - Spina::ImageCollection.new(images: images.collect(&:convert_to_part!)) + Spina::ImageCollection.new(images: images.collect(&:convert_to_partable!)) end end From 02f47b5e0f8a77a1e03bd0b28ae69415870909fb Mon Sep 17 00:00:00 2001 From: codefactor-io Date: Wed, 7 Apr 2021 14:07:46 +0000 Subject: [PATCH 21/21] [CodeFactor] Apply fixes --- .../conferences/conferences_controller.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/controllers/spina/admin/conferences/conferences_controller.rb b/app/controllers/spina/admin/conferences/conferences_controller.rb index 6d7ff307..9835af2d 100644 --- a/app/controllers/spina/admin/conferences/conferences_controller.rb +++ b/app/controllers/spina/admin/conferences/conferences_controller.rb @@ -8,18 +8,18 @@ module Conferences class ConferencesController < ApplicationController PARTS_PARAMS = [ :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, - { images_attributes: %i[filename signed_blob_id image_id alt], - content_attributes: [ - :name, :title, - { parts_attributes: [ - :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, - { images_attributes: %i[filename signed_blob_id image_id alt] } - ] } - ] } + images_attributes: %i[filename signed_blob_id image_id alt], + content_attributes: [ + :name, :title, + parts_attributes: [ + :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id, + images_attributes: %i[filename signed_blob_id image_id alt] + ] + ] ].freeze CONTENT_PARAMS = Spina.config.locales.inject({}) { |params, locale| params.merge("#{locale}_content_attributes": [*PARTS_PARAMS]) } - PARAMS = [:start_date, :finish_date, :name, { **CONTENT_PARAMS, - events_attributes: %i[id name start_datetime finish_datetime description location] }].freeze + PARAMS = [:start_date, :finish_date, :name, **CONTENT_PARAMS, + events_attributes: %i[id name start_datetime finish_datetime description location] ].freeze PARTS = %w[text submission_url submission_email_address submission_date submission_text gallery sponsors].freeze before_action :set_conference, only: %i[edit update destroy]