From 81783912b230321020213e85ca9939d7762ad133 Mon Sep 17 00:00:00 2001 From: Aaron Brethorst Date: Fri, 9 Aug 2024 08:13:16 -0700 Subject: [PATCH 1/4] Simplify creation of in page tab bars (sub tabs) --- app/helpers/application_helper.rb | 11 +++-------- app/helpers/layouts_helper.rb | 10 ++++++++++ app/views/admins/_survey_tabs.html.erb | 6 ++---- app/views/layouts/application.html.erb | 16 +++++++++------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1077237..1b9a767 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,5 +1,5 @@ module ApplicationHelper - + def title(t = nil) if t.nil? @title @@ -8,11 +8,6 @@ def title(t = nil) end end - def back_link(title, path) - @back_link_title = title - @back_link_path = path - end - def severity_to_string(sev) case sev when 2 @@ -23,9 +18,9 @@ def severity_to_string(sev) return "Severe" else return "Unknown" - end + end end - + def value_or_blank_rep(val) if val.blank? "—" diff --git a/app/helpers/layouts_helper.rb b/app/helpers/layouts_helper.rb index ea3f4f3..d867a86 100644 --- a/app/helpers/layouts_helper.rb +++ b/app/helpers/layouts_helper.rb @@ -6,4 +6,14 @@ def parent_layout(layout) output = render(template: File.join("layouts", layout)) self.output_buffer = ActionView::OutputBuffer.new(output) end + + def back_link(title, path) + @back_link_title = title + @back_link_path = path + end + + def sub_tab(name:, path:) + @sub_tabs ||= [] + @sub_tabs << { name:, path: } + end end \ No newline at end of file diff --git a/app/views/admins/_survey_tabs.html.erb b/app/views/admins/_survey_tabs.html.erb index 39986b1..ea8b745 100644 --- a/app/views/admins/_survey_tabs.html.erb +++ b/app/views/admins/_survey_tabs.html.erb @@ -1,4 +1,2 @@ -<%= render Navigation::TabsComponent.new([ - { name: "Designer", path: admin_study_survey_path(@survey.study, @survey) }, - { name: "Responses", path: admin_study_survey_survey_responses_path(@survey.study, @survey) } -]) %> \ No newline at end of file +<% sub_tab(name: "Designer", path: admin_study_survey_path(@survey.study, @survey)) %> +<% sub_tab(name: "Responses", path: admin_study_survey_survey_responses_path(@survey.study, @survey)) %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index dd73ae8..e35a703 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -39,13 +39,15 @@ <% end %>
-
-
- <% if @back_link_title.present? && @back_link_path.present? %> - <%= render Navigation::BackLinkComponent.new(title: @back_link_title, link: @back_link_path) %> - <% end %> -

<%= @title %>

-
+
+ <% if @back_link_title.present? && @back_link_path.present? %> + <%= render Navigation::BackLinkComponent.new(title: @back_link_title, link: @back_link_path) %> + <% end %> +

<%= @title %>

+ + <% if defined?(@sub_tabs) && @sub_tabs.count > 0 %> + <%= render Navigation::TabsComponent.new(@sub_tabs) %> + <% end %>
From a16cdaa19d4825efb39cfab0e365f6fe2d7ada40 Mon Sep 17 00:00:00 2001 From: Aaron Brethorst Date: Fri, 9 Aug 2024 14:53:29 -0700 Subject: [PATCH 2/4] Adds a data list component for showing lists of information --- app/components/data/data_list_component.html.erb | 8 ++++++++ app/components/data/data_list_component.rb | 8 ++++++++ spec/components/data/data_list_component_spec.rb | 13 +++++++++++++ spec/rails_helper.rb | 2 ++ 4 files changed, 31 insertions(+) create mode 100644 app/components/data/data_list_component.html.erb create mode 100644 app/components/data/data_list_component.rb create mode 100644 spec/components/data/data_list_component_spec.rb diff --git a/app/components/data/data_list_component.html.erb b/app/components/data/data_list_component.html.erb new file mode 100644 index 0000000..c213d42 --- /dev/null +++ b/app/components/data/data_list_component.html.erb @@ -0,0 +1,8 @@ +
+ <% @items.each do |i| %> +
+ <%= i[:name] %> + <%= i[:value] %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/components/data/data_list_component.rb b/app/components/data/data_list_component.rb new file mode 100644 index 0000000..fe95d3f --- /dev/null +++ b/app/components/data/data_list_component.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class Data::DataListComponent < ViewComponent::Base + def initialize(items) + super() + @items = items + end +end diff --git a/spec/components/data/data_list_component_spec.rb b/spec/components/data/data_list_component_spec.rb new file mode 100644 index 0000000..1de896d --- /dev/null +++ b/spec/components/data/data_list_component_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Data::DataListComponent, type: :component do + it "renders something useful" do + expect( + render_inline(described_class.new([{ name: "Hello world", value: "Foo bar" }])).to_html + ).to include( + "Hello world" + ) + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index f3c3bc1..c39d9ed 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -10,6 +10,7 @@ require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! +require "view_component/test_helpers" Rails.root.glob('spec/support/**/*.rb').sort.each { |f| require f } @@ -30,6 +31,7 @@ config.infer_spec_type_from_file_location! config.filter_rails_from_backtrace! + config.include ViewComponent::TestHelpers, type: :component config.include ApiHelper, type: :request config.include RequestHelper, type: :request config.include ModelsHelper From 5acc84e0f7dee8f2fa3342c142cbde6d2a6a499b Mon Sep 17 00:00:00 2001 From: Aaron Brethorst Date: Fri, 9 Aug 2024 14:54:02 -0700 Subject: [PATCH 3/4] Adds another valid embedded data field for external surveys --- .../admins/questions/fields/_external_survey.html.erb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/views/admins/questions/fields/_external_survey.html.erb b/app/views/admins/questions/fields/_external_survey.html.erb index 50e560f..67bc123 100644 --- a/app/views/admins/questions/fields/_external_survey.html.erb +++ b/app/views/admins/questions/fields/_external_survey.html.erb @@ -22,6 +22,12 @@ option_name: "embedded_data_fields", options: form.object.embedded_data_fields ) %> -

Valid values for embedded data are: region_id, route_id, stop_id, user_id.

+

+ Valid values for embedded data are: + current_location, + region_id, + route_id, + stop_id, + user_id +

- From 4f664ef6c2029a2403a54b05bf226228e6c199ee Mon Sep 17 00:00:00 2001 From: Aaron Brethorst Date: Fri, 9 Aug 2024 14:54:55 -0700 Subject: [PATCH 4/4] Adds new options to the Survey model to configure visibility of surveys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow them to be shown on maps or stops—or neither. And restrict the list of stops and routes. --- app/controllers/admins/surveys_controller.rb | 11 +- app/models/survey.rb | 7 +- app/views/admins/surveys/_form.html.erb | 21 +++- app/views/admins/surveys/show.html.erb | 102 +++++++++++-------- app/views/api/v1/surveys/index.json.jbuilder | 14 ++- 5 files changed, 111 insertions(+), 44 deletions(-) diff --git a/app/controllers/admins/surveys_controller.rb b/app/controllers/admins/surveys_controller.rb index 63e386e..ba638b5 100644 --- a/app/controllers/admins/surveys_controller.rb +++ b/app/controllers/admins/surveys_controller.rb @@ -41,7 +41,16 @@ def destroy private def survey_params - params.require(:survey).permit(:name, :enabled, :extra_data, questions: []) + params.require(:survey).permit( + :name, + :enabled, + :extra_data, + :show_on_map, + :show_on_stops, + :visible_stop_list, + :visible_route_list, + questions: [] + ) end def load_study diff --git a/app/models/survey.rb b/app/models/survey.rb index a50390b..efc035e 100644 --- a/app/models/survey.rb +++ b/app/models/survey.rb @@ -4,7 +4,12 @@ class Survey < ApplicationRecord # Extra Data jsonb_accessor(:extra_data, { - name: :string + name: :string, + + show_on_map: :boolean, + show_on_stops: :boolean, + visible_stop_list: :string, + visible_route_list: :string }) validates :name, presence: true diff --git a/app/views/admins/surveys/_form.html.erb b/app/views/admins/surveys/_form.html.erb index f6cb3c2..659cce4 100644 --- a/app/views/admins/surveys/_form.html.erb +++ b/app/views/admins/surveys/_form.html.erb @@ -1,8 +1,27 @@ -<%= form_with model: @survey, url: admin_study_surveys_path(@study) do |f| %> +<% url = @survey.persisted? ? admin_study_survey_path(@study, @survey) : admin_study_surveys_path(@study) %> +<%= form_with model: @survey, url: url do |f| %>
<%= render Forms::ErrorsComponent.new(errors: @survey.errors.full_messages) %> <%= render Forms::TextFieldComponent.new(form: f, method: :name, autofocus: true) %> <%= render Forms::CheckboxComponent.new(form: f, method: :available) %> + + <%= render Forms::CheckboxComponent.new(form: f, method: :show_on_map) %> + <%= render Forms::CheckboxComponent.new(form: f, method: :show_on_stops) %> + +
+ <%= render Forms::TextFieldComponent.new(form: f, method: :visible_stop_list) %> +
+ Optional, comma separated list of stop IDs that this survey should be visible on. When blank, it implies visibility on all stops. +
+
+ +
+ <%= render Forms::TextFieldComponent.new(form: f, method: :visible_route_list) %> +
+ Optional, comma separated list of route IDs that this survey should be visible on. When blank, it implies visibility on all routes. +
+
+ <%= render Forms::ButtonBarComponent.new(f) %>
<% end %> \ No newline at end of file diff --git a/app/views/admins/surveys/show.html.erb b/app/views/admins/surveys/show.html.erb index 57b5eeb..ec4e22f 100644 --- a/app/views/admins/surveys/show.html.erb +++ b/app/views/admins/surveys/show.html.erb @@ -1,48 +1,70 @@ <% title @survey.name %> <% back_link "Back to Study", admin_study_path(@survey.study) %> - <%= render 'admins/survey_tabs' %> -
-
- <%= link_to "New Text Field", new_admin_study_survey_question_path(@survey.study, @survey, content: 'text'), class: 'oba-btn' %> - <%= link_to "New Label", new_admin_study_survey_question_path(@survey.study, @survey, content: 'label'), class: 'oba-btn' %> - <%= link_to "New Radio List", new_admin_study_survey_question_path(@survey.study, @survey, content: 'radio'), class: 'oba-btn' %> - <%= link_to "New Checkbox List", new_admin_study_survey_question_path(@survey.study, @survey, content: 'checkbox'), class: 'oba-btn' %> - <%= link_to "New External Survey", new_admin_study_survey_question_path(@survey.study, @survey, content: 'external_survey'), class: 'oba-btn' %> +
+
+
+

Settings

+
+ <%= link_to "Edit", edit_admin_study_survey_path(@survey.study, @survey), class: "oba-btn oba-btn--sm" %> +
+
+ +
+ <%= render Data::DataListComponent.new( + [ + { name: "Name", value: @survey.name }, + { name: "Show on Map", value: @survey.show_on_map? ? "Yes" : "No" }, + { name: "Show on Stops", value: @survey.show_on_stops? ? "Yes" : "No" }, + { name: "Visible stop list", value: @survey.visible_stop_list }, + { name: "Visible route list", value: @survey.visible_route_list }, + ] + ) %> +
- <% if @survey.questions.blank? %> - <%= render Containers::EmptyStateComponent.new( - title: "No Survey Questions", - description: "Add survey questions to this survey to collect data from participants." - ) %> - <% else %> -
- <% @survey.questions.each do |sq| %> -
-
-
- <%= render("icons/grip_vertical_solid", classes: "w-4 h-4 fill-gray-500") %> -
-
-

Q<%= sq.position %>: <%= sq.content.type.titleize %>

-
-
- <%= link_to "Edit", edit_admin_study_survey_question_path(@survey.study, @survey, sq), class: "link text-sm" %> +
+
+ <%= link_to "New Text Field", new_admin_study_survey_question_path(@survey.study, @survey, content: 'text'), class: 'oba-btn' %> + <%= link_to "New Label", new_admin_study_survey_question_path(@survey.study, @survey, content: 'label'), class: 'oba-btn' %> + <%= link_to "New Radio List", new_admin_study_survey_question_path(@survey.study, @survey, content: 'radio'), class: 'oba-btn' %> + <%= link_to "New Checkbox List", new_admin_study_survey_question_path(@survey.study, @survey, content: 'checkbox'), class: 'oba-btn' %> + <%= link_to "New External Survey", new_admin_study_survey_question_path(@survey.study, @survey, content: 'external_survey'), class: 'oba-btn' %> +
+ + <% if @survey.questions.blank? %> + <%= render Containers::EmptyStateComponent.new( + title: "No Survey Questions", + description: "Add survey questions to this survey to collect data from participants." + ) %> + <% else %> +
+ <% @survey.questions.each do |sq| %> +
+
+
+ <%= render("icons/grip_vertical_solid", classes: "w-4 h-4 fill-gray-500") %> +
+
+

Q<%= sq.position %>: <%= sq.content.type.titleize %>

+
+
+ <%= link_to "Edit", edit_admin_study_survey_question_path(@survey.study, @survey, sq), class: "link text-sm" %> +
+ <%= render partial_for_field_preview(sq), question: sq %>
- <%= render partial_for_field_preview(sq), question: sq %> -
- <% end %> -
- <% end %> -
+ <% end %> +
+ <% end %> +
+
\ No newline at end of file diff --git a/app/views/api/v1/surveys/index.json.jbuilder b/app/views/api/v1/surveys/index.json.jbuilder index 487b46f..0f55577 100644 --- a/app/views/api/v1/surveys/index.json.jbuilder +++ b/app/views/api/v1/surveys/index.json.jbuilder @@ -1,6 +1,18 @@ json.surveys do json.array! @surveys do |survey| - json.extract! survey, :id, :name, :created_at + json.extract! survey, :id, :name, :created_at, :updated_at, :show_on_map, :show_on_stops + + if survey.visible_stop_list.blank? + json.visible_stop_list nil + else + json.visible_stop_list survey.visible_stop_list&.split(',')&.map(&:strip) + end + + if survey.visible_route_list.blank? + json.visible_route_list nil + else + json.visible_route_list survey.visible_route_list&.split(',')&.map(&:strip) + end json.study do json.extract! survey.study, :id, :name, :description