Skip to content

Commit 0679a03

Browse files
committed
Display person use count for project in author match #4943
1 parent 0e18ebd commit 0679a03

5 files changed

Lines changed: 55 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This project <em>does not yet</em> adhere to [Semantic Versioning](https://semve
1414
- CSD: Added a button to load the associated CO when the identifier is already in use by another CO
1515
- Ctrl+v to paste images and documents in "Drop [image/doc] here"
1616
- New descriptors: character states' thumbnails [#4796]
17+
- Project usage count for authors in Match Author task of New Source [#4943]
1718

1819
### Changed
1920

@@ -41,6 +42,7 @@ This project <em>does not yet</em> adhere to [Semantic Versioning](https://semve
4142
[#4928]: https://github.com/SpeciesFileGroup/taxonworks/issues/4928
4243
[#4929]: https://github.com/SpeciesFileGroup/taxonworks/issues/4929
4344
[#4932]: https://github.com/SpeciesFileGroup/taxonworks/issues/4932
45+
[#4943]: https://github.com/SpeciesFileGroup/taxonworks/issues/4943
4446
[#4946]: https://github.com/SpeciesFileGroup/taxonworks/issues/4946
4547
[#4959]: https://github.com/SpeciesFileGroup/taxonworks/issues/4959
4648

app/controllers/people_controller.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,7 @@ def author_match
126126
people = Queries::Person::Filter.new(author_match_params).all.to_a
127127

128128
@people = Utilities::PersonNameMatch.sort_by_match(people, first_name, last_name)
129-
130-
render :index
129+
@project_use_counts = Person.project_use_counts(@people.map(&:id), sessions_current_project_id)
131130
end
132131

133132
# GET /people/download

app/javascript/vue/tasks/sources/new_source/components/bibtex/AuthorMatchModal.vue

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@
8484
x-small
8585
/>
8686
</a>
87+
<span
88+
class="use-count"
89+
:title="`${person.use_count} project ${person.use_count === 1 ? 'use' : 'uses'}`"
90+
>{{ person.use_count }} {{ person.use_count === 1 ? 'use' : 'uses' }}</span>
8791
</div>
8892
</div>
8993
<div
@@ -371,16 +375,31 @@ async function searchMatches(row, claimedRoleIds) {
371375
}
372376
}
373377
378+
// Preserves the backend's name-group order (e.g. exact matches before fuzzy),
379+
// but within each group of identically-named people sorts by project use count descending.
380+
const sortByUsage = (matches) => {
381+
const groupOrder = {}
382+
matches.forEach((p) => {
383+
const key = p.cached || p.name || ''
384+
if (!(key in groupOrder)) groupOrder[key] = Object.keys(groupOrder).length
385+
})
386+
return [...matches].sort((a, b) => {
387+
const groupDiff = groupOrder[a.cached || a.name || ''] - groupOrder[b.cached || b.name || '']
388+
if (groupDiff !== 0) return groupDiff
389+
return (b.use_count || 0) - (a.use_count || 0)
390+
})
391+
}
392+
374393
const handleResult = (people) => {
375394
if (!firstReturned) {
376395
firstReturned = true
377-
row.matches = people
396+
row.matches = sortByUsage(people)
378397
row.isSearching = false
379398
claimExistingRole(people)
380399
} else {
381400
const existingIds = new Set(row.matches.map((p) => p.id))
382401
const incoming = people.filter((p) => !existingIds.has(p.id))
383-
row.matches = [...row.matches, ...incoming]
402+
row.matches = sortByUsage([...row.matches, ...incoming])
384403
row.isFuzzySearchPending = false
385404
claimExistingRole(incoming)
386405
}
@@ -500,6 +519,11 @@ td {
500519
font-size: 0.85em;
501520
}
502521
522+
.use-count {
523+
font-size: 0.8em;
524+
color: var(--text-muted-color);
525+
}
526+
503527
.create-cell {
504528
min-width: 250px;
505529
}

app/models/person.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,28 @@ def is_collector?
440440
collector_roles.any?
441441
end
442442

443+
# @param [Array] person_ids
444+
# @param [Integer] project_id
445+
# @return [Hash]
446+
# person_id => count of in-project roles (direct + via project sources)
447+
def self.project_use_counts(person_ids, project_id)
448+
return {} if person_ids.empty?
449+
450+
direct = Role.where(person_id: person_ids, project_id:)
451+
.group(:person_id).count
452+
453+
via_source = Role
454+
.where(person_id: person_ids, project_id: nil)
455+
.joins("JOIN sources ON roles.role_object_id = sources.id AND roles.role_object_type = 'Source'")
456+
.joins('JOIN project_sources ON sources.id = project_sources.source_id')
457+
.where(project_sources: { project_id: })
458+
.group(:person_id).count
459+
460+
(direct.keys | via_source.keys).index_with do |id|
461+
(direct[id] || 0) + (via_source[id] || 0)
462+
end
463+
end
464+
443465
def role_counts(project_id)
444466
{
445467
in_project: self.roles.where(project_id:).group(:type).count,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
json.array!(@people) do |person|
2+
json.partial! '/people/base_attributes', person: person
3+
json.use_count @project_use_counts[person.id] || 0
4+
end

0 commit comments

Comments
 (0)