Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion app/assets/stylesheets/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ input[type=checkbox] {
accent-color: theme-color-level(primary, 0);
}

.easy-autocomplete {
width: 100%;
}

.placement-form {
#incertae-sedis {
display: none;
}

&:has([name="placement[incertae_sedis]"][value="true"]:checked) {
#standard-placement {
display: none;
}

#incertae-sedis {
display: block;
}
}
}

#dashboard-actions, .btn {
.fa, .fas, .far, .fal, .fad, .fab {
min-width: 1.5em;
Expand Down Expand Up @@ -378,4 +398,3 @@ nav.navbar {
[data-rank=g] { color: hsl(280deg, 80%, 30%); }
[data-rank=s] { color: hsl(320deg, 80%, 30%); }
}

12 changes: 5 additions & 7 deletions app/controllers/names_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,17 @@ class NamesController < ApplicationController
before_action(:authenticate_can_edit_validated!, only: %i[update edit_links])

# GET /names/autocomplete.json?q=Maco
# GET /names/autocomplete.json?q=Allo&rank=genus
# GET /names/autocomplete.json?q=Pseu&minimum_rank=class
# GET /names/autocomplete.json?q=Allo&ranks=genus
# GET /names/autocomplete.json?q=Pseu&ranks=domain,phylum,class

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've combined these two params into a single param. So you just specify a list of ranks that are allowed. For known placements that list is just ["genus"] if name is a species etc.

def autocomplete
name = params[:q].downcase
rank = params[:rank]&.downcase
minimum_rank = params[:minimum_rank]&.downcase
@names =
Name.where('LOWER(name) LIKE ?', "#{name}%")
.or(Name.where('LOWER(name) LIKE ?', "% #{name}%"))
.limit(20)
@names = @names.where(rank: rank) if rank
minimum_ranks = Name.ranks_at_or_above(minimum_rank)
@names = @names.where(rank: minimum_ranks) if minimum_ranks
if params.key?(:ranks)
@names = @names.where(rank: params[:ranks].downcase.split(','))
end
@names = @names.where(redirect: nil)
end

Expand Down
8 changes: 5 additions & 3 deletions app/controllers/placements_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ def update
def create_or_update(back_action)
par = params.require(:placement).permit(
:incertae_sedis, :incertae_sedis_text,
:parent, :preferred, :publication
:parent, :incertae_sedis_parent, :preferred, :publication
)
@placement.incertae_sedis = par[:incertae_sedis].presence
@placement.incertae_sedis_text = par[:incertae_sedis_text]
par[:parent] = par[:incertae_sedis_parent] if @placement.incertae_sedis?
if @name.placement
@placement.preferred = par[:preferred] if current_user.curator?
else
Expand Down Expand Up @@ -103,7 +104,8 @@ def create_or_update(back_action)
old_placement.update!(preferred: false)
end
@name.update!(
parent: @placement.parent, assigned_in: @placement.publication,
parent: @placement.incertae_sedis? ? nil : @placement.parent,
assigned_in: @placement.publication,
)
end
rescue
Expand All @@ -125,7 +127,7 @@ def prefer
@name.placement.try(:update!, preferred: false)
@placement.update!(preferred: true)
@name.update!(
parent: @placement.parent,
parent: @placement.incertae_sedis? ? nil : @placement.parent,
assigned_in: @placement.publication
)
ok = true
Expand Down
1 change: 0 additions & 1 deletion app/javascript/packs/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ import "packs/network";
import "packs/styling";
import "packs/copyable";
import "channels/index.js";

6 changes: 3 additions & 3 deletions app/javascript/packs/autocomplete.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@

$(document).on("turbolinks:load", function() {
var eac_options = {
adjustWidth: false,
url: function(phrase) {
var data = $($(event)[0]["srcElement"]).data();
var what = data["autocomplete"];
var url = new URL(what + "/autocomplete.json", ROOT_PATH);
url.searchParams.set("q", phrase);
if(data["rank"]) { url.searchParams.set("rank", data["rank"]); }
if(data["minimumRank"]) {
url.searchParams.set("minimum_rank", data["minimumRank"]);
if(data["ranks"] !== undefined) {
url.searchParams.set("ranks", data["ranks"].join(","));
}
return url.toString();
},
Expand Down
14 changes: 6 additions & 8 deletions app/models/name.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1018,9 +1018,7 @@ def lineage(with_self: false)
def lineage_parent
return parent if parent

if incertae_sedis? && incertae_sedis =~ /Incertae sedis \((.+)\)/
self.class.find_by_variants($1)
end
placement.parent if incertae_sedis?
end

def type_name_alt_placement
Expand Down Expand Up @@ -1486,11 +1484,9 @@ def harmonize_register_and_status
end

def ensure_consistent_placement
placement_incertae_sedis = incertae_sedis

if parent_id.present? || placement_incertae_sedis.present?
if parent_id.present?
pp = placements.where(
parent_id: parent_id, incertae_sedis: placement_incertae_sedis
parent_id: parent_id, incertae_sedis: false
).first
if pp.present?
if pp.preferred?
Expand All @@ -1503,10 +1499,12 @@ def ensure_consistent_placement
Placement.new(
name_id: id,
parent_id: parent_id,
incertae_sedis: placement_incertae_sedis,
incertae_sedis: false,
preferred: true
).save
end
elsif placements.where(preferred: true, incertae_sedis: true).exists?
true
else
# Conservatively preserve as alternative placement
placements.update(preferred: false)
Expand Down
13 changes: 9 additions & 4 deletions app/models/name/quality_checks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,17 @@ class QcWarning
inconsistent_parent_rank: {
message: ->(_w, n) {
<<~MSG
The parent rank (#{n.parent.inferred_rank}) is inconsistent
The parent rank (#{n.placement.parent.inferred_rank}) is inconsistent
with the rank of this name (#{n.inferred_rank})
MSG
},
area: :nomenclature,
rules: %w[7a 7b],
scope: ->(_w, n) { n.rank? && n.parent&.rank? },
scope: ->(_w, n) {
n.rank? && n.placement&.parent&.rank?
},
failure: ->(_w, n) {
n.class.ranks.index(n.rank) != n.class.ranks.index(n.parent.rank) + 1
!n.placement.allowed_parent_ranks.include?(n.placement.parent.rank)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a previous version of this pull req I added a new quality check for the incertae sedis rank. WIth the new Placement#allowed_parent_ranks method they can easily be combined in a single quality check. @lmrodriguezr Please double check that this is OK :)

}
}.merge(@@link_to_edit_parent),
# - Rules 7c and 7d are implied by the structure of the SeqCode Registry
Expand All @@ -141,7 +143,10 @@ class QcWarning
link_to: ->(_w, n) { [:edit_parent, n] },
recommendations: %w[7],
scope: ->(_w, n) { n.rank? && !n.top_rank? },
failure: ->(_w, n) { !n.incertae_sedis? && !n.parent.present? }
failure: ->(_w, n) {
parent = n.incertae_sedis? ? n.placement.parent : n.parent
!parent.present?
}
},

# Section 3. Naming of Taxa
Expand Down
25 changes: 17 additions & 8 deletions app/models/placement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,12 @@ class Placement < ApplicationRecord
)
belongs_to(:publication, optional: true)
validates(:name, presence: true)
validates(:parent, presence: true, unless: :incertae_sedis?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This removes the ability to have incertae sedis without a parent. There are almost no cases of that. Wouldn't at least a domain placement always be possible?

validates(:parent, presence: true)

has_rich_text(:incertae_sedis_text)
validates(:incertae_sedis_text, presence: true, if: :incertae_sedis?)
validates(:incertae_sedis, presence: true, allow_nil: true)
validates(
:incertae_sedis, absence: {
if: :parent,
message: 'cannot be declared if the parent taxon is set'
}
:incertae_sedis, inclusion: { in: [true, false] }
)
validates(:preferred, uniqueness: { scope: :name_id, if: :preferred? })

Expand All @@ -23,7 +19,20 @@ class Placement < ApplicationRecord
def incertae_sedis_html
return '' unless incertae_sedis?

incertae_sedis.gsub(/(incertae sedis)/i, '<i>\\1</i>').html_safe
ActionController::Base.helpers.safe_join(
['<i>incertae sedis</i>'.html_safe, (" (#{parent.name})" if parent)].compact
)
end

def allowed_parent_ranks(incertae_sedis: incertae_sedis?)
rank_index = name&.rank_index
return [] unless rank_index && rank_index.positive?

if incertae_sedis
Name.ranks.take(rank_index - 1)
else
[Name.ranks[rank_index - 1]]
end
end

def downwards?
Expand All @@ -36,6 +45,6 @@ def downwards?
private

def harmonize_name_parent
name.update(parent: parent) if preferred
name.update(parent: incertae_sedis? ? nil : parent) if preferred
end
end
40 changes: 15 additions & 25 deletions app/models/tutorial/batch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ def param_names

# Deal with foreign keys
if j['parent'] &&
j['parent'] =~ /^incertae sedis( \((Archaea|Bacteria)\))?/
j['incertae_sedis'] = j['parent']
j['parent'] = nil
match = j['parent'].match(
/^incertae sedis( \((Archaea|Bacteria)\))?/
)
j['incertae_sedis'] = true
j['parent'] = match[2]
end
j['parent'] &&= Name.new(name: j['parent'])
if j['nomenclatural_type_type'].to_s.downcase == 'name' &&
Expand All @@ -80,7 +82,7 @@ def ephemeral_names
name_attributes = i.except('parent', 'incertae_sedis')
placement_attributes = {
parent: i['parent'],
incertae_sedis: i['incertae_sedis'],
incertae_sedis: i['incertae_sedis'] || false,
preferred: true
}
if i['incertae_sedis'].present?
Expand Down Expand Up @@ -348,7 +350,6 @@ def batch_step_01(params, user)
default_pars = { status: 0, created_by: user }
param_names.each do |par|
new_par = {}
placement_par = nil

# Parents
if par['parent']
Expand All @@ -357,16 +358,14 @@ def batch_step_01(params, user)
parent = Name.new(default_pars.merge(name: par['parent'].name))
parent.save!
end
placement_par = {
parent: parent,
incertae_sedis: nil
}
elsif par['incertae_sedis']
placement_par = {
parent: nil,
incertae_sedis: par['incertae_sedis'],
incertae_sedis_text: par['description']
}
name = Name.find_by_variants(par['name'])
placement = name.placements.find_or_initialize_by(parent: parent)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplication. I wanna tackle this in another PR as previously discussed.

name.placements.where(preferred: true).where.not(id: placement.id)
.find_each { |current| current.update!(preferred: false) }
placement.update!(
incertae_sedis: par['incertae_sedis'] || false,
incertae_sedis_text: par['description'], preferred: true
)
end

# Nomenclatural types
Expand All @@ -387,16 +386,7 @@ def batch_step_01(params, user)
end
end

name = Name.find_by_variants(par['name'])
name.update!(new_par)
if placement_par
placement = name.placements.find_or_initialize_by(
parent: placement_par[:parent],
incertae_sedis: placement_par[:incertae_sedis]
)
name.placements.where.not(id: placement.id).update_all(preferred: false)
placement.update!(placement_par.merge(preferred: true))
end
Name.find_by_variants(par['name']).update!(new_par)
end

# If all is good, go to next step
Expand Down
8 changes: 5 additions & 3 deletions app/views/dev/autocomplete.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<label for="autocomplete-phylum">Phylum only</label>
<input id="autocomplete-phylum" class="form-control" type="text"
value="Pseu" data-behavior="autocomplete"
data-autocomplete="names" data-rank="phylum">
data-autocomplete="names" data-ranks='["phylum"]'>
</div>
</div>

Expand All @@ -35,15 +35,17 @@
<label for="autocomplete-class-or-above">Class or above</label>
<input id="autocomplete-class-or-above" class="form-control" type="text"
value="Bac" data-behavior="autocomplete"
data-autocomplete="names" data-minimum-rank="class">
data-autocomplete="names"
data-ranks='<%= Name.ranks_at_or_above('class').to_json %>'>
<small class="form-text text-muted">Domain, phylum, or class.</small>
</div>

<div class="form-group">
<label for="autocomplete-genus-or-above">Genus or above</label>
<input id="autocomplete-genus-or-above" class="form-control" type="text"
value="Escher" data-behavior="autocomplete"
data-autocomplete="names" data-minimum-rank="genus">
data-autocomplete="names"
data-ranks='<%= Name.ranks_at_or_above('genus').to_json %>'>
<small class="form-text text-muted">
Domain through genus; excludes species and subspecies.
</small>
Expand Down
Loading
Loading