Skip to content

Commit

Permalink
Merge pull request #454 from girder/more-efficient-annotation-counts
Browse files Browse the repository at this point in the history
Speed up item list annotation counts.
  • Loading branch information
manthey authored Jun 8, 2020
2 parents c2869b2 + f23b13d commit ef57a5a
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from girder.api import access
from girder.api.describe import describeRoute, autoDescribeRoute, Description
from girder.api.rest import Resource, loadmodel, filtermodel, setResponseHeader
from girder.constants import AccessType, SortDir
from girder.constants import AccessType, SortDir, TokenScope
from girder.exceptions import ValidationException, RestException, AccessException
from girder.models.item import Item
from girder.models.user import User
Expand Down Expand Up @@ -60,6 +60,7 @@ def __init__(self):
self.route('DELETE', ('item', ':id'), self.deleteItemAnnotations)
self.route('GET', ('old',), self.getOldAnnotations)
self.route('DELETE', ('old',), self.deleteOldAnnotations)
self.route('GET', ('counts',), self.getItemListAnnotationCounts)

@describeRoute(
Description('Search for annotations.')
Expand Down Expand Up @@ -565,3 +566,20 @@ def getOldAnnotations(self, age, versions):
def deleteOldAnnotations(self, age, versions):
setResponseTimeLimit(86400)
return Annotation().removeOldAnnotations(True, age, versions)

@access.public(scope=TokenScope.DATA_READ)
@autoDescribeRoute(
Description('Get annotation counts for a list of items.')
.param('items', 'A comma-separated list of item ids.')
.errorResponse()
)
def getItemListAnnotationCounts(self, items):
user = self.getCurrentUser()
results = {}
for itemId in items.split(','):
item = Item().load(itemId, level=AccessType.READ, user=user)
annotations = Annotation().findWithPermissions(
{'_active': {'$ne': False}, 'itemId': item['_id']},
user=self.getCurrentUser(), level=AccessType.READ, limit=-1)
results[itemId] = annotations.count()
return results
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,18 @@ import '../stylesheets/itemList.styl';
wrap(ItemListWidget, 'render', function (render) {
render.apply(this, _.rest(arguments));

function addLargeImageAnnotationBadge(item, parent) {
restRequest({
type: 'GET',
url: 'annotation',
data: {
itemId: item.id,
limit: -1
},
error: null
}).done((result, status, jqxhr) => {
const numAnnotations = +jqxhr.getResponseHeader('Girder-Total-Count') || 0;
const thumbnail = $('a[g-item-cid="' + item.cid + '"] .large_image_thumbnail', parent).first();

let badge = thumbnail.find('.large_image_annotation_badge');
if (badge.length === 0) {
badge = $(`<div class="large_image_annotation_badge"></div>`).appendTo(thumbnail);
}
// update badge
badge
.attr('title', `${numAnnotations} annotation${numAnnotations === 1 ? '' : 's'}`)
.text(numAnnotations)
.toggleClass('hidden', numAnnotations === 0);
});
function addLargeImageAnnotationBadge(item, parent, numAnnotations) {
const thumbnail = $('a[g-item-cid="' + item.cid + '"] .large_image_thumbnail', parent).first();

let badge = thumbnail.find('.large_image_annotation_badge');
if (badge.length === 0) {
badge = $(`<div class="large_image_annotation_badge hidden"></div>`).appendTo(thumbnail);
}
// update badge
badge
.attr('title', `${numAnnotations} annotation${numAnnotations === 1 ? '' : 's'}`)
.text(numAnnotations)
.toggleClass('hidden', !numAnnotations);
}

largeImageAnnotationConfig.getSettings((settings) => {
Expand All @@ -50,12 +39,35 @@ wrap(ItemListWidget, 'render', function (render) {
return;
}

_.each(items, (item) => {
if (item.get('largeImage')) {
item.getAccessLevel(function () {
addLargeImageAnnotationBadge(item, parent);
const needCounts = items.filter((item) => item._annotationCount === undefined && item.has('largeImage')).map((item) => {
item._annotationCount = null; // pending
return item.id;
});
let promise;
if (!needCounts.length) {
promise = $.Deferred().resolve({});
} else {
promise = restRequest({
type: 'POST',
url: 'annotation/counts',
data: {
items: needCounts.join(',')
},
headers: { 'X-HTTP-Method-Override': 'GET' },
error: null
}).done((resp) => {
Object.entries(resp).forEach(([id, count]) => {
this.collection.get(id)._annotationCount = count;
});
}
});
}
promise.then(() => {
this.collection.forEach((item) => {
if (item._annotationCount !== undefined) {
addLargeImageAnnotationBadge(item, parent, item._annotationCount);
}
});
return null;
});
});
});
Expand Down

0 comments on commit ef57a5a

Please sign in to comment.