Skip to content

Commit

Permalink
Change loading of users with annotations from rendering to API
Browse files Browse the repository at this point in the history
This commit changes the way the user filters are loaded in Largo. Rather then being loaded from within the Controller, it is loaded from the API once the user clicks on the annotation filter.
  • Loading branch information
dbrembilla committed Jan 2, 2025
1 parent c8a16bc commit 9f76329
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 31 deletions.
53 changes: 53 additions & 0 deletions src/Http/Controllers/Api/Projects/GetUsersWithAnnotations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Biigle\Modules\Largo\Http\Controllers\Api\Projects;

use Biigle\Http\Controllers\Api\Controller;
use Biigle\ImageAnnotationLabel;
use Biigle\VideoAnnotationLabel;
use Biigle\Project;
use Illuminate\Http\Request;

class GetUsersWithAnnotations extends Controller
{
/**
* Show all image annotations of the volume that have a specific label attached.
*
* @api {get} projects/image/users-with-annotations/:vid Get users with annotations
* @apiGroup Projects
* @apiName ShowUsersWithImageAnnotations
* @apiParam {Number} pid The Project ID
* @apiPermission projectMember
* @apiDescription Returns the users with annotations
*
* @param Request $request
* @param int $pid Project ID
* @return \Illuminate\Http\Response
*/
public function index(Request $request, $pid)
{
$project = Project::findOrFail($pid);
$this->authorize('access', $project);
$volumes = $project->volumes()->pluck('id');

$usersWithImageAnnotations = ImageAnnotationLabel::query()
->join('image_annotations', 'image_annotations.id', '=', 'image_annotation_labels.annotation_id')
->join('images', 'image_annotations.image_id', '=', 'images.id')
->whereIn('images.volume_id', $volumes)
->join('users', 'image_annotation_labels.user_id', '=', 'users.id')
->distinct('image_annotation_labels.user_id')
->select('image_annotation_labels.user_id', 'users.lastname', 'users.firstname')
->get()->toArray();

$usersWithVideoAnnotations = VideoAnnotationLabel::query()
->join('video_annotations', 'video_annotations.id', '=', 'video_annotation_labels.annotation_id')
->join('videos', 'video_annotations.video_id', '=', 'videos.id')
->whereIn('videos.volume_id', $volumes)
->join('users', 'video_annotation_labels.user_id', '=', 'users.id')
->distinct('video_annotation_labels.user_id')
->select('video_annotation_labels.user_id', 'users.lastname', 'users.firstname')
->get()->toArray();

return array_merge($usersWithImageAnnotations, $usersWithVideoAnnotations);
}
};
54 changes: 54 additions & 0 deletions src/Http/Controllers/Api/Volumes/GetUsersWithAnnotations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Biigle\Modules\Largo\Http\Controllers\Api\Volumes;

use Biigle\Http\Controllers\Api\Controller;
use Biigle\ImageAnnotationLabel;
use Biigle\Volume;
use Biigle\MediaType;
use Illuminate\Http\Request;

class GetUsersWithAnnotations extends Controller
{
/**
* Show all image annotations of the volume that have a specific label attached.
*
* @api {get} volumes/image/users-with-annotations/:vid Get users with annotations
* @apiGroup Volumes
* @apiName ShowUsersWithImageAnnotations
* @apiParam {Number} vid The volume ID
* @apiPermission projectMember
* @apiDescription Returns the users with annotations
*
* @param Request $request
* @param int $vid Volume ID
* @param int $lid Label ID
* @return \Illuminate\Http\Response
*/
public function index(Request $request, $vid)
{
$volume = Volume::findOrFail($vid);
$this->authorize('access', $volume);
if ($volume->media_type_id == MediaType::imageId()){
$usersWithAnnotations = ImageAnnotationLabel::query()
->join('image_annotations', 'image_annotations.id', '=', 'image_annotation_labels.annotation_id')
->join('images', 'image_annotations.image_id', '=', 'images.id')
->where('images.volume_id', $vid)
->join('users', 'image_annotation_labels.user_id', '=', 'users.id')
->distinct('image_annotation_labels.user_id')
->select('image_annotation_labels.user_id', 'users.lastname', 'users.firstname')
->get();
} else {
$usersWithAnnotations = VideoAnnotationLabel::query()
->join('video_annotations', 'video_annotations.id', '=', 'video_annotation_labels.annotation_id')
->join('videos', 'video_annotations.video_id', '=', 'videos.id')
->whereIn('videos.volume_id', $vid)
->join('users', 'video_annotation_labels.user_id', '=', 'users.id')
->distinct('video_annotation_labels.user_id')
->select('video_annotation_labels.user_id', 'users.lastname', 'users.firstname')
->get();
}

return $usersWithAnnotations;
}
};
10 changes: 0 additions & 10 deletions src/Http/Controllers/Views/Projects/LargoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,12 @@ public function index(Request $request, $id)

$shapes = Shape::pluck('name', 'id');

$usersWithAnnotations = ImageAnnotationLabel::query()
->join('image_annotations', 'image_annotations.id', '=', 'image_annotation_labels.annotation_id')
->join('images', 'image_annotations.image_id', '=', 'images.id')
->where('images.volume_id', $id)
->join('users', 'image_annotation_labels.user_id', '=', 'users.id')
->distinct('image_annotation_labels.user_id')
->select('image_annotation_labels.user_id', 'users.lastname', 'users.firstname')
->get();

return view('largo::project', [
'project' => $project,
'labelTrees' => $labelTrees,
'target' => $project,
'patchUrlTemplate' => $patchUrlTemplate,
'shapes' => $shapes,
'usersWithAnnotations' => $usersWithAnnotations,
]);
}
}
10 changes: 0 additions & 10 deletions src/Http/Controllers/Views/Volumes/LargoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,13 @@ public function index(Request $request, $id)
unset($shapes[$wholeframeId]);
}

$usersWithAnnotations = ImageAnnotationLabel::query()
->join('image_annotations', 'image_annotations.id', '=', 'image_annotation_labels.annotation_id')
->join('images', 'image_annotations.image_id', '=', 'images.id')
->where('images.volume_id', $id)
->join('users', 'image_annotation_labels.user_id', '=', 'users.id')
->distinct('image_annotation_labels.user_id')
->select('image_annotation_labels.user_id', 'users.lastname', 'users.firstname')
->get();

return view('largo::show', [
'volume' => $volume,
'projects' => $projects,
'labelTrees' => $labelTrees,
'target' => $volume,
'patchUrlTemplate' => $patchUrlTemplate,
'shapes' => $shapes,
'usersWithAnnotations' => $usersWithAnnotations,
]);
}
}
8 changes: 8 additions & 0 deletions src/Http/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
'uses' => 'Projects\FilterVideoAnnotationsByLabelController@index',
]);

$router->get('projects/users-with-annotations/{pid}', [
'uses' => 'Projects\GetUsersWithAnnotations@index',
]);

$router->get('volumes/{id}/annotations/sort/outliers/{id2}', [
'uses' => 'Volumes\SortAnnotationsByOutliersController@index',
]);
Expand All @@ -69,6 +73,10 @@
'uses' => 'Volumes\FilterImageAnnotationsByLabelController@index',
]);

$router->get('volumes/users-with-annotations/{vid}', [
'uses' => 'Volumes\GetUsersWithAnnotations@index',
]);

$router->post('volumes/{id}/largo', [
'uses' => 'Volumes\LargoController@save',
]);
Expand Down
4 changes: 4 additions & 0 deletions src/resources/assets/js/api/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ export default Vue.resource('api/v1/projects{/id}/largo', {}, {
method: 'GET',
url: 'api/v1/projects{/id}/annotations/sort/similarity',
},
getUsersWithAnnotations: {
method: 'GET',
url: 'api/v1/projects/users-with-annotations{/id}',
}
});
4 changes: 4 additions & 0 deletions src/resources/assets/js/api/volumes.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ export default Vue.resource('api/v1/volumes{/id}/largo', {}, {
method: 'GET',
url: 'api/v1/volumes{/id}/annotations/sort/similarity',
},
getUsersWithAnnotations: {
method: 'GET',
url: 'api/v1/volumes/users-with-annotations{/id}',
}
});
28 changes: 19 additions & 9 deletions src/resources/assets/js/components/annotationFilter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
selected="Shapes"
v-model="selectedFilter"
@change="changeSelectedFilter"
@click="loadApiFilters"
>
<option
v-for="value in this.allowedFilters"
Expand All @@ -31,6 +32,7 @@
class="form-control"
v-model="selectedFilterValue"
>

<option
v-for="(filter_name, filter_id) in this.activeFilter"
:value="[filter_name, filter_id]"
Expand All @@ -46,27 +48,21 @@
</template>
<script>
import {Messages} from '../import';
import ProjectsApi from '../api/projects';
import VolumesApi from '../api/volumes';
export default {
data() {
//TODO: add more filters here. See https://github.com/biigle/largo/issues/66
let possibleShapes = biigle.$require('largo.availableShapes');
//Load users with annotations
let usersWithAnnotations = biigle.$require('largo.usersWithAnnotations')
let possibleUsers = {};
usersWithAnnotations.forEach(function (user) {
possibleUsers[user.user_id] = user.lastname + ' ' + user.firstname
});
return {
selectedAnnotationShape: null,
selectedAnnotationUser: null,
allowedFilters: ['Shape', 'User'],
filterValues: {
user_id: possibleUsers,
shape_id: possibleShapes,
user_id: {},
},
shapeToValue : {
Shape: 'shape_id',
Expand All @@ -84,6 +80,20 @@ export default {
changeSelectedFilter() {
this.activeFilter = this.filterValues[this.shapeToValue[this.selectedFilter]]
},
loadApiFilters() {
//Load here filters that should be loaded AFTER the page is rendered
let volumeId = biigle.$require('largo.volumeId');
let usersWithAnnotationsPromise;
if (typeof volumeId === 'number'){
usersWithAnnotationsPromise = VolumesApi.getUsersWithAnnotations({id: volumeId});
} else {
let projectId = biigle.$require('largo.projectId');
usersWithAnnotationsPromise = ProjectsApi.getUsersWithAnnotations({id: projectId});
}
let usersWithAnnotations = usersWithAnnotationsPromise.then((response) =>
response.data.forEach((user) => this.filterValues['user_id'][user.user_id] = user.lastname + ' ' + user.firstname)
);
},
addFilter() {
if (!this.selectedFilterValue){
Messages.danger("No filter selected!")
Expand Down
1 change: 0 additions & 1 deletion src/resources/views/project.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
biigle.$declare('largo.showVideoAnnotationRoute', '{{ route('show-video-annotation', '') }}/');
biigle.$declare('largo.patchUrlTemplate', '{{$patchUrlTemplate}}');
biigle.$declare('largo.availableShapes', {!! $shapes !!});
biigle.$declare('largo.usersWithAnnotations', {!! $usersWithAnnotations !!});
</script>
@endpush

Expand Down
1 change: 0 additions & 1 deletion src/resources/views/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
biigle.$declare('largo.showVideoAnnotationRoute', '{{ route('show-video-annotation', '') }}/');
biigle.$declare('largo.patchUrlTemplate', '{{$patchUrlTemplate}}');
biigle.$declare('largo.availableShapes', {!! $shapes !!})
biigle.$declare('largo.usersWithAnnotations', {!! $usersWithAnnotations !!});
</script>
@endpush

Expand Down

0 comments on commit 9f76329

Please sign in to comment.