diff --git a/app/classes/api2/project_api.rb b/app/classes/api2/project_api.rb index 12dcad5cf4..7a0438f232 100644 --- a/app/classes/api2/project_api.rb +++ b/app/classes/api2/project_api.rb @@ -43,6 +43,7 @@ def query_params has_summary: parse(:boolean, :has_summary), title_has: parse(:string, :title_has, help: 1), summary_has: parse(:string, :summary_has, help: 1), + field_slip_prefix_has: parse(:string, :field_slip_prefix_has, help: 1), comments_has: parse(:string, :comments_has, help: 1) } end @@ -52,6 +53,7 @@ def create_params { title: parse(:string, :title, limit: 100), summary: parse(:string, :summary, default: ""), + field_slip_prefix: parse(:string, :field_slip_prefix, default: ""), user: @user } end @@ -60,7 +62,8 @@ def update_params parse_update_params { title: parse(:string, :set_title, limit: 100, not_blank: true), - summary: parse(:string, :set_summary) + summary: parse(:string, :set_summary), + field_slip_prefix: parse(:string, :set_field_slip_prefix) } end diff --git a/app/classes/query/project_base.rb b/app/classes/query/project_base.rb index 0a8a73eb4e..294eb87a05 100644 --- a/app/classes/query/project_base.rb +++ b/app/classes/query/project_base.rb @@ -17,6 +17,7 @@ def parameter_declarations has_summary?: :boolean, title_has?: :string, summary_has?: :string, + field_slip_prefix_has?: :string, comments_has?: :string, member?: User ) @@ -59,6 +60,10 @@ def initialize_search_parameters "projects.summary", params[:summary_has] ) + add_search_condition( + "projects.field_slip_prefix", + params[:field_slip_prefix_has] + ) add_search_condition( "CONCAT(comments.summary,COALESCE(comments.comment,''))", params[:comments_has], diff --git a/app/classes/query/project_pattern_search.rb b/app/classes/query/project_pattern_search.rb index aff4d7ce11..b951128798 100644 --- a/app/classes/query/project_pattern_search.rb +++ b/app/classes/query/project_pattern_search.rb @@ -15,7 +15,8 @@ def initialize_flavor def search_fields "CONCAT(" \ "projects.title," \ - "COALESCE(projects.summary,'')" \ + "COALESCE(projects.summary,'')," \ + "COALESCE(projects.field_slip_prefix,'')" \ ")" end end diff --git a/app/controllers/field_slips_controller.rb b/app/controllers/field_slips_controller.rb new file mode 100644 index 0000000000..1c241a9605 --- /dev/null +++ b/app/controllers/field_slips_controller.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +class FieldSlipsController < ApplicationController + before_action :set_field_slip, only: [:edit, :update, :destroy] + before_action :login_required, except: [:show] + + # GET /field_slips or /field_slips.json + def index + @field_slips = FieldSlip.includes( + [{ observation: [:location, :name, :namings, :rss_log, :user] }, + :project, :user] + ) + end + + # GET /field_slips/1 or /field_slips/1.json + def show + obs = nil + if params[:id].match?(/^\d+$/) + set_field_slip + else + @field_slip = FieldSlip.find_by(code: params[:id].upcase) + obs = @field_slip&.observation + end + if @field_slip + redirect_to(observation_url(id: obs.id)) if obs + else + redirect_to(new_field_slip_url(code: params[:id].upcase)) + end + end + + # GET /field_slips/new + def new + @field_slip = FieldSlip.new + @field_slip.code = params[:code].upcase if params.include?(:code) + end + + # GET /field_slips/1/edit + def edit + return unless @field_slip.user != User.current + + redirect_to(field_slip_url(id: @field_slip.id)) + end + + # POST /field_slips or /field_slips.json + def create + @field_slip = FieldSlip.new(field_slip_params) + + respond_to do |format| + check_project_membership + check_for_last_obs + if params[:commit] == :field_slip_last_obs.t + @field_slip.observation = ObservationView.last(User.current) + end + if @field_slip.save + format.html do + if params[:commit] == :field_slip_create_obs.t + redirect_to(new_observation_url(field_code: @field_slip.code)) + else + redirect_to(field_slip_url(@field_slip), + notice: :field_slip_created.t) + end + end + format.json { render(:show, status: :created, location: @field_slip) } + else + format.html { render(:new, status: :unprocessable_entity) } + format.json do + render(json: @field_slip.errors, status: :unprocessable_entity) + end + end + end + end + + # PATCH/PUT /field_slips/1 or /field_slips/1.json + def update + respond_to do |format| + check_for_last_obs + if @field_slip.update(field_slip_params) + format.html do + if params[:commit] == :field_slip_create_obs.t + redirect_to(new_observation_url(field_code: @field_slip.code)) + else + redirect_to(field_slip_url(@field_slip), + notice: :field_slip_updated.t) + end + end + format.json { render(:show, status: :ok, location: @field_slip) } + else + format.html { render(:edit, status: :unprocessable_entity) } + format.json do + render(json: @field_slip.errors, status: :unprocessable_entity) + end + end + end + end + + # DELETE /field_slips/1 or /field_slips/1.json + def destroy + if @field_slip.user != User.current + redirect_to(field_slip_url(id: @field_slip.id)) + return + end + + @field_slip.destroy! + + respond_to do |format| + format.html do + redirect_to(field_slips_url, + notice: :field_slip_destroyed.t) + end + format.json { head(:no_content) } + end + end + + private + + # Use callbacks to share common setup or constraints between actions. + def set_field_slip + @field_slip = FieldSlip.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def field_slip_params + params.require(:field_slip).permit(:observation_id, :project_id, :code) + end + + def check_project_membership + project = @field_slip&.project + return unless project&.can_join?(User.current) + + project.user_group.users << User.current + flash_notice(:field_slip_welcome.t(title: project.title)) + end + + def check_for_last_obs + return unless params[:commit] == :field_slip_last_obs.t + + obs = ObservationView.last(User.current) + @field_slip.observation = obs + project = @field_slip.project + return unless obs && project&.user_can_add_observation?(obs, User.current) + + project.add_observation(obs) + end +end diff --git a/app/controllers/herbarium_records_controller.rb b/app/controllers/herbarium_records_controller.rb index 3c48599eac..53026ec630 100644 --- a/app/controllers/herbarium_records_controller.rb +++ b/app/controllers/herbarium_records_controller.rb @@ -194,7 +194,9 @@ def default_herbarium_record end def default_accession_number - if @observation.collection_numbers.length == 1 + if @observation.field_slips.length == 1 + @observation.field_slips.first.code + elsif @observation.collection_numbers.length == 1 @observation.collection_numbers.first.format_name else "MO #{@observation.id}" diff --git a/app/controllers/observations_controller/new_and_create.rb b/app/controllers/observations_controller/new_and_create.rb index 2bbd133d9e..cb0594b75e 100644 --- a/app/controllers/observations_controller/new_and_create.rb +++ b/app/controllers/observations_controller/new_and_create.rb @@ -46,10 +46,12 @@ def new @reasons = @naming.init_reasons @images = [] @good_images = [] + @field_code = params[:field_code] init_specimen_vars init_project_vars_for_create init_list_vars defaults_from_last_observation_created + add_field_slip_project(@field_code) end ############################################################################## @@ -83,6 +85,14 @@ def defaults_from_last_observation_created end end + def add_field_slip_project(code) + project = FieldSlip.find_by(code: code)&.project + return unless project + return unless project&.member?(User.current) + + @project_checks[project.id] = true + end + ############################################################################## public @@ -102,20 +112,14 @@ def create success = false if @name && !@vote.value.nil? && !validate_object(@vote) success = false if @bad_images != [] success = false if success && !save_observation(@observation) - - # Once observation is saved we can save everything else. - if success - @observation.log(:log_observation_created) - # should always succeed - save_everything_else(params.dig(:naming, :reasons)) - strip_images! if @observation.gps_hidden - flash_notice(:runtime_observation_success.t(id: @observation.id)) - redirect_to_next_page - - # If anything failed reload the form. - else - reload_new_form(params.dig(:naming, :reasons)) - end + return reload_new_form(params.dig(:naming, :reasons)) unless success + + @observation.log(:log_observation_created) + save_everything_else(params.dig(:naming, :reasons)) + strip_images! if @observation.gps_hidden + update_field_slip(@observation, params[:field_code]) + flash_notice(:runtime_observation_success.t(id: @observation.id)) + redirect_to_next_page end ############################################################################## @@ -309,10 +313,19 @@ def reload_new_form(reasons) @reasons = @naming.init_reasons(reasons) @images = @bad_images @new_image.when = @observation.when + @field_code = params[:field_code] init_specimen_vars_for_reload init_project_vars_for_create init_project_vars_for_reload(@observation) init_list_vars_for_reload(@observation) render(action: :new, location: new_observation_path(q: get_query_param)) end + + def update_field_slip(observation, field_code) + field_slip = FieldSlip.find_by(code: field_code) + return unless field_slip + + field_slip.observation = observation + field_slip.save + end end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index cf46e90f85..71363e21e1 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -101,6 +101,7 @@ def update upload_image_if_present @summary = params[:project][:summary] + @field_slip_prefix = params[:project][:field_slip_prefix] if valid_title && valid_where && valid_dates if @project.update(project_create_params) override_fixed_dates @@ -242,7 +243,7 @@ def show_selected_projects(query, args = {}) def project_create_params params.require(:project). - permit(:title, :summary, :open_membership, + permit(:title, :summary, :open_membership, :field_slip_prefix, "start_date(1i)", "start_date(2i)", "start_date(3i)", "end_date(1i)", "end_date(2i)", "end_date(3i)") end diff --git a/app/helpers/field_slips_helper.rb b/app/helpers/field_slips_helper.rb new file mode 100644 index 0000000000..2663a6b811 --- /dev/null +++ b/app/helpers/field_slips_helper.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module FieldSlipsHelper + def last_observation + return unless User.current + + ObservationView.last(User.current) + end +end diff --git a/app/models/field_slip.rb b/app/models/field_slip.rb new file mode 100644 index 0000000000..85e56a96c9 --- /dev/null +++ b/app/models/field_slip.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class FieldSlip < AbstractModel + belongs_to :observation + belongs_to :project + belongs_to :user + + validates :code, uniqueness: true + validates :code, presence: true + validate do |field_slip| + unless field_slip.code.match?(/[^\d.-]/) + errors.add(:code, :format, message: :field_slip_code_format_error.t) + end + end + + def code=(val) + self[:code] = val.upcase + return if project + + prefix_match = code.match(/(^.+)[ -]\d+$/) + return unless prefix_match + + self.project = Project.find_by(field_slip_prefix: prefix_match[1]) + end + + def title + code + end + + def projects + @projects ||= find_projects + end + + def find_projects + result = Project.includes(:project_members).where( + project_members: { user: User.current } + ).order(:title).pluck(:title, :id) + return result unless project && result.exclude?([project.title, project.id]) + + result.unshift([project.title, project.id]) + end +end diff --git a/app/models/observation.rb b/app/models/observation.rb index 4ea81e7c84..d2c2d68c30 100644 --- a/app/models/observation.rb +++ b/app/models/observation.rb @@ -199,6 +199,7 @@ class Observation < AbstractModel # rubocop:disable Metrics/ClassLength has_many :observation_collection_numbers, dependent: :destroy has_many :collection_numbers, through: :observation_collection_numbers + has_many :field_slips, dependent: :destroy has_many :observation_herbarium_records, dependent: :destroy has_many :herbarium_records, through: :observation_herbarium_records @@ -503,6 +504,7 @@ class Observation < AbstractModel # rubocop:disable Metrics/ClassLength scope :show_includes, lambda { strict_loading.includes( :collection_numbers, + :field_slips, { comments: :user }, { external_links: { external_site: { project: :user_group } } }, { herbarium_records: [{ herbarium: :curators }, :user] }, @@ -1076,8 +1078,9 @@ def add_image(img) def remove_image(img) if images.include?(img) || thumb_image_id == img.id images.delete(img) - update(thumb_image: images.empty? ? nil : images.first) \ - if thumb_image_id == img.id + if thumb_image_id == img.id + update(thumb_image: images.empty? ? nil : images.first) + end notify_users(:removed_image) end img @@ -1105,6 +1108,7 @@ def turn_off_specimen_if_no_more_records return unless collection_numbers.empty? return unless herbarium_records.empty? return unless sequences.empty? + return unless field_slips.empty? update(specimen: false) end diff --git a/app/models/observation_view.rb b/app/models/observation_view.rb index 0d78793dec..d8ffaba26f 100644 --- a/app/models/observation_view.rb +++ b/app/models/observation_view.rb @@ -30,4 +30,9 @@ def self.update_view_stats(obs_id, user_id, reviewed = nil) create!(args) end end + + def self.last(user) + view = ObservationView.where(user:).order(last_view: :desc).first + view&.observation + end end diff --git a/app/models/project.rb b/app/models/project.rb index 83645515cd..3afb9c550b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -10,14 +10,15 @@ # # == Attributes # -# id:: Locally unique numerical id, starting at 1. -# created_at:: Date/time it was first created. -# updated_at:: Date/time it was last updated. -# user:: User that created it. -# admin_group:: UserGroup of admins. -# user_group:: UserGroup of members. -# title:: Title string. -# summary:: Summary of purpose. +# id:: Locally unique numerical id, starting at 1. +# created_at:: Date/time it was first created. +# updated_at:: Date/time it was last updated. +# user:: User that created it. +# admin_group:: UserGroup of admins. +# user_group:: UserGroup of members. +# title:: Title string. +# summary:: Summary of purpose. +# field_slip_prefix:: Prefix for associated field slip codes # open_membership Enable users to add themselves, disable shared editing # location:: # image:: @@ -79,6 +80,7 @@ class Project < AbstractModel # rubocop:disable Metrics/ClassLength has_many :species_lists, through: :project_species_lists before_destroy :orphan_drafts + validates :field_slip_prefix, uniqueness: true, allow_blank: true scope :show_includes, lambda { strict_loading.includes( @@ -96,6 +98,16 @@ def text_name title.to_s end + # Ensure that field_slip_prefix is uppercase and at most 60 + # characters so in the worst case the prefix plus 5 single byte + # characters is under 255 bytes (limit in SQL assuming all prefix + # characters are 4-byte unicode). + def field_slip_prefix=(val) + self[:field_slip_prefix] = if val && val.strip != "" + val.strip.upcase[0, 60] + end + end + # Same as +text_name+ but with id tacked on to make unique. def unique_text_name "#{text_name} (#{id || "?"})" diff --git a/app/views/controllers/api2/_project.json.jbuilder b/app/views/controllers/api2/_project.json.jbuilder index aea0882d8c..9206c80476 100644 --- a/app/views/controllers/api2/_project.json.jbuilder +++ b/app/views/controllers/api2/_project.json.jbuilder @@ -4,6 +4,7 @@ json.id(object.id) json.type("project") json.title(object.title.to_s) json.summary(object.summary.to_s.tpl_nodiv) if object.summary.present? +json.title(object.field_slip_prefix.to_s) if object.field_slip_prefix.present? json.created_at(object.created_at.try(&:utc)) json.updated_at(object.updated_at.try(&:utc)) if detail diff --git a/app/views/controllers/api2/_project.xml.builder b/app/views/controllers/api2/_project.xml.builder index 8aa73f69e3..b05f0c623c 100644 --- a/app/views/controllers/api2/_project.xml.builder +++ b/app/views/controllers/api2/_project.xml.builder @@ -8,6 +8,7 @@ xml.tag!( ) do xml_string(xml, :title, object.title) xml_html_string(xml, :summary, object.summary.to_s.tpl_nodiv) + xml_string(xml, :field_slip_prefix, object.field_slip_prefix) xml_datetime(xml, :created_at, object.created_at) xml_datetime(xml, :updated_at, object.updated_at) if detail diff --git a/app/views/controllers/field_slips/_field_slip.html.erb b/app/views/controllers/field_slips/_field_slip.html.erb new file mode 100644 index 0000000000..1b38068074 --- /dev/null +++ b/app/views/controllers/field_slips/_field_slip.html.erb @@ -0,0 +1,26 @@ +
+

+ <%= :PROJECT.t %>: + <% if field_slip.project %> + <%= link_to_object(field_slip.project) %> + <% else %> + <%= :field_slip_no_project.t %> + <% end %> +
+ <% if field_slip.user %> + <%= :field_slip_creator.t %>: + <%= link_to(field_slip.user.legal_name, user_path(field_slip.user_id)) %>
+ <% end %> + <%= :OBSERVATION.t %>: + <% if field_slip.observation %> + <%= link_to(field_slip.observation.unique_format_name.t, observation_path(field_slip.observation)) %> +

+ <% else %> + <%= :field_slip_no_observation.t %> + <% end %> +

+
diff --git a/app/views/controllers/field_slips/_field_slip.json.jbuilder b/app/views/controllers/field_slips/_field_slip.json.jbuilder new file mode 100644 index 0000000000..37c5521152 --- /dev/null +++ b/app/views/controllers/field_slips/_field_slip.json.jbuilder @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +json.extract!(field_slip, :id, :observation_id, :project_id, :code, + :created_at, :updated_at) +json.url(field_slip_url(field_slip, format: :json)) diff --git a/app/views/controllers/field_slips/_form.html.erb b/app/views/controllers/field_slips/_form.html.erb new file mode 100644 index 0000000000..59bc645288 --- /dev/null +++ b/app/views/controllers/field_slips/_form.html.erb @@ -0,0 +1,48 @@ +<% +action = controller.action_name +%> + +<%= form_with(model: field_slip) do |form| %> + <% if field_slip.errors.any? %> +
+ <%= "#{pluralize(field_slip.errors.count, + :error.t, plural: :errors.t)} #{:field_slip_errors.t}" %>: + +
+ <% end %> + + <%= text_field_with_label(form: form, field: :code) %> + + <% if @field_slip.projects %> + <%= select_with_label(form: form, field: :project_id, + options: @field_slip.projects) %> + <% end %> + + <%= submit_button(form: form, button: :field_slip_create_obs.t, + class: "mt-5") if action == "new" %> + +
+ <% if field_slip.observation %> +
+ <%= render(partial: "field_slips/obs_thumbnail", + locals: { obs: field_slip.observation, form: form, + button: :field_slip_keep_obs.t }) %> +
+ <% end %> + <% if last_observation %> +
+ <%= render(partial: "field_slips/obs_thumbnail", + locals: { obs: last_observation, form: form, + button: :field_slip_last_obs.t }) %> +
+ <% end %> +
+ + <%= submit_button(form: form, button: :field_slip_create_obs.t, + class: "my-5") if action == "edit" %> + +<% end %> diff --git a/app/views/controllers/field_slips/_obs_thumbnail.erb b/app/views/controllers/field_slips/_obs_thumbnail.erb new file mode 100644 index 0000000000..92683315e8 --- /dev/null +++ b/app/views/controllers/field_slips/_obs_thumbnail.erb @@ -0,0 +1,12 @@ + <%= tag.div(class: "panel panel-default") do + concat(panel_block_heading( + heading: submit_button(form: form, button: button) + )) + concat(tag.div(class: "thumbnail-container") do + interactive_image(obs.thumb_image_id, votes: false, + image_link: observation_path(obs)) + end) if obs.thumb_image_id.present? + concat(tag.div(class: "panel-body") do + link_to(obs.unique_format_name.t, observation_path(obs)) + end) + end %> diff --git a/app/views/controllers/field_slips/edit.html.erb b/app/views/controllers/field_slips/edit.html.erb new file mode 100644 index 0000000000..06277d96bc --- /dev/null +++ b/app/views/controllers/field_slips/edit.html.erb @@ -0,0 +1,10 @@ +<% add_page_title(:field_slip_editing.t) %> + +<%= render "form", field_slip: @field_slip %> + +
+ +
+ <%= link_to :field_slip_show.t, @field_slip %> | + <%= link_to :field_slip_index.t, field_slips_path %> +
diff --git a/app/views/controllers/field_slips/index.html.erb b/app/views/controllers/field_slips/index.html.erb new file mode 100644 index 0000000000..7d5d005e47 --- /dev/null +++ b/app/views/controllers/field_slips/index.html.erb @@ -0,0 +1,17 @@ +<% add_page_title(:FIELD_SLIPS.t) %> + +<% if notice %> +

<%= notice %>

+<% end %> + +
+ <% @field_slips.each do |field_slip| %> + <%= :field_slip_code.t %>: + <%= field_slip.code %> + <%= render field_slip %> + <%= link_to :field_slip_show.t, field_slip %> +
+ <% end %> +
+ +<%= link_to :field_slip_new.t, new_field_slip_path %> diff --git a/app/views/controllers/field_slips/index.json.jbuilder b/app/views/controllers/field_slips/index.json.jbuilder new file mode 100644 index 0000000000..374336fa00 --- /dev/null +++ b/app/views/controllers/field_slips/index.json.jbuilder @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +json.array!(@field_slips, partial: "field_slips/field_slip", as: :field_slip) diff --git a/app/views/controllers/field_slips/new.html.erb b/app/views/controllers/field_slips/new.html.erb new file mode 100644 index 0000000000..8bffb043e0 --- /dev/null +++ b/app/views/controllers/field_slips/new.html.erb @@ -0,0 +1,9 @@ +<% add_page_title(:field_slip_new.t) %> + +<%= render "form", field_slip: @field_slip %> + +
+ +
+ <%= link_to :field_slip_index.t, field_slips_path %> +
diff --git a/app/views/controllers/field_slips/show.html.erb b/app/views/controllers/field_slips/show.html.erb new file mode 100644 index 0000000000..217f358a5e --- /dev/null +++ b/app/views/controllers/field_slips/show.html.erb @@ -0,0 +1,17 @@ +<% add_page_title(@field_slip.code) %> + +<% if notice %> +

<%= notice %>

+<% end %> + +

<%= "#{:FIELD_SLIP.t}: #{@field_slip.code}" %>

+ +<%= render @field_slip %> + +
+ <%= link_to :field_slip_index.t, field_slips_path %> + <% if @field_slip.user == User.current %> + | <%= link_to :field_slip_edit.t, edit_field_slip_path(@field_slip) %> + | <%= button_to :field_slip_destroy.t, @field_slip, method: :delete %> + <% end %> +
diff --git a/app/views/controllers/field_slips/show.json.jbuilder b/app/views/controllers/field_slips/show.json.jbuilder new file mode 100644 index 0000000000..1fb4d693be --- /dev/null +++ b/app/views/controllers/field_slips/show.json.jbuilder @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +json.partial!("field_slips/field_slip", field_slip: @field_slip) diff --git a/app/views/controllers/observations/_form.html.erb b/app/views/controllers/observations/_form.html.erb index 9c6586f20e..10654dc267 100644 --- a/app/views/controllers/observations/_form.html.erb +++ b/app/views/controllers/observations/_form.html.erb @@ -31,6 +31,8 @@ image_upload_localization = { } ) do |f| %> + <%= hidden_field_tag(:field_code, @field_code) %> + <%= submit_button(form: f, button: button_name, center: true) %> <%= render(partial: "observations/form/when", locals: { f: f }) %> diff --git a/app/views/controllers/observations/show/_observation_details.erb b/app/views/controllers/observations/show/_observation_details.erb index e78db2ae9b..b2ebdf8d39 100644 --- a/app/views/controllers/observations/show/_observation_details.erb +++ b/app/views/controllers/observations/show/_observation_details.erb @@ -16,6 +16,20 @@ end end %> + <% if obs.field_slips.present? %> + <%= tag.div(class: "obs-field-slips", id: "observation_field_slips") do + if obs.field_slips.count == 1 + concat(tag.span("#{:FIELD_SLIP.t}: ")) + concat(link_to_object(obs.field_slips[0])) + else + concat([tag.span("#{:FIELD_SLIPS.t}:"), tag.br].safe_join) + obs.field_slips.each do |field_slip| + concat(tag.div(link_to_object(field_slip), class: "indent")) + end + end + end %> + <% end %> + <%= tag.p(class: "obs-specimen", id: "observation_specimen_available") do if obs.specimen :show_observation_specimen_available.t diff --git a/app/views/controllers/projects/_form.html.erb b/app/views/controllers/projects/_form.html.erb index 11e86bd301..f881c2fef4 100644 --- a/app/views/controllers/projects/_form.html.erb +++ b/app/views/controllers/projects/_form.html.erb @@ -12,6 +12,9 @@ <%= text_area_with_label(form: f, field: :summary, rows: 5, label: :SUMMARY.t + ":") %> + <%= text_field_with_label(form: f, field: :field_slip_prefix, + label: :FIELD_SLIP_PREFIX.t + ":") %> + <%= render(partial: "shared/textilize_help") %> <%= autocompleter_field(form: f, field: :place_name, label: :WHERE.t + ":", diff --git a/app/views/controllers/projects/show.html.erb b/app/views/controllers/projects/show.html.erb index 0ec5e0457f..239e5ac510 100644 --- a/app/views/controllers/projects/show.html.erb +++ b/app/views/controllers/projects/show.html.erb @@ -36,6 +36,7 @@ violations_button_class = <% end %>

<%= :show_project_created_at.t %>: <%= @project.created_at.web_date %>

+

<%= :show_project_field_slip_prefix.t %>: <%= @project.field_slip_prefix %>

<% if @project.observations.any? %> <%= link_to("#{@project.observations.length} #{:OBSERVATIONS.l}", diff --git a/app/views/controllers/shared/_matrix_box.erb b/app/views/controllers/shared/_matrix_box.erb index ba3b65c23e..2559af3fdb 100644 --- a/app/views/controllers/shared/_matrix_box.erb +++ b/app/views/controllers/shared/_matrix_box.erb @@ -18,19 +18,28 @@ if presenter else image_args = {} end + header_components = passed_args[:header].presence || [] + footer_components = + if passed_args[:footer] == false + [] + else + passed_args[:footer].presence || + [matrix_box_log_footer(presenter), + matrix_box_identify_footer(identify, presenter.id)] + end %> <%= matrix_box(columns: columns, id: object_id) do tag.div(class: "panel panel-default") do [ + *header_components, tag.div(class: "panel-sizing") do [ matrix_box_image(image, **image_args), matrix_box_details(presenter, object_id, identify), ].safe_join end, - matrix_box_log_footer(presenter), - matrix_box_identify_footer(identify, presenter.id) + *footer_components ].safe_join end end %> diff --git a/app/views/controllers/visual_models/_form.html.erb b/app/views/controllers/visual_models/_form.html.erb index c3d0884057..5caf2e75f2 100644 --- a/app/views/controllers/visual_models/_form.html.erb +++ b/app/views/controllers/visual_models/_form.html.erb @@ -1,8 +1,8 @@ <%= form_with(model: visual_model) do |f| %> <% if visual_model.errors.any? %>

-

<%= pluralize(visual_model.errors.count, "error") %> prohibited this visual_model from being saved:

- + <%= "#{pluralize(visual_model.errors.count, + :error.t, plural: :errors.t)} #{:visual_model_errors.t}" %>: