Skip to content

Commit ce0b83f

Browse files
authored
Use tags to get next/prev unreviewed files (#363)
* Make tags available to all components * Pass current tags to unreviewed neighbor endpoint * Use tags for sidebar recording list * Simplify next/prev filter by tag logic * Indicate when a tag filter is active * Add tag text template to shared list
1 parent ade13a9 commit ce0b83f

File tree

5 files changed

+125
-43
lines changed

5 files changed

+125
-43
lines changed

client/src/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default defineComponent({
2121
configuration ,
2222
loadCurrentUser,
2323
loadReviewerMaterials,
24+
loadFilterTags,
2425
} = useState();
2526
const getShared = async () => {
2627
sharedList.value = (await getRecordings(true)).data.items;
@@ -55,6 +56,7 @@ export default defineComponent({
5556
};
5657
onMounted(async () => {
5758
checkLogin();
59+
loadFilterTags();
5860
});
5961
router.afterEach((guard) => {
6062
if (guard.path.includes("spectrogram")) {

client/src/components/RecordingList.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export default defineComponent({
1515
showSubmittedRecordings,
1616
myRecordingsDisplay,
1717
sharedRecordingsDisplay,
18+
filterTags,
19+
sharedFilterTags,
1820
} = useState();
1921
const editingRecording: Ref<EditingRecording | null> = ref(null);
2022
@@ -33,9 +35,9 @@ export default defineComponent({
3335
3436
const fetchRecordings = async () => {
3537
const params = buildListParams();
36-
const recordings = await getRecordings(false, params);
38+
const recordings = await getRecordings(false, { ...params, tags: filterTags.value });
3739
recordingList.value = recordings.data.items;
38-
const shared = await getRecordings(true, { ...params, public: true });
40+
const shared = await getRecordings(true, { ...params, public: true, tags: sharedFilterTags.value });
3941
sharedList.value = shared.data.items;
4042
};
4143
onMounted(() => fetchRecordings());

client/src/use/useState.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ const reviewerMaterials = ref('');
111111

112112
const transparencyThreshold = ref(0); // 0-100 percentage
113113

114+
const FILTER_TAG_STORAGE_KEY = 'bataiFilterTags';
115+
const SHARED_FILTER_TAG_STORAGE_KEY = 'bataiSharedFilterTags';
116+
117+
const filterTags: Ref<string[]> = ref([]);
118+
const sharedFilterTags: Ref<string[]> = ref([]);
119+
114120
type AnnotationState = "" | "editing" | "creating" | "disabled";
115121
export default function useState() {
116122
const setAnnotationState = (state: AnnotationState) => {
@@ -204,6 +210,17 @@ export default function useState() {
204210
}
205211
}
206212

213+
function saveFilterTags() {
214+
localStorage.setItem(FILTER_TAG_STORAGE_KEY, JSON.stringify(filterTags.value));
215+
localStorage.setItem(SHARED_FILTER_TAG_STORAGE_KEY, JSON.stringify(sharedFilterTags.value));
216+
}
217+
218+
function loadFilterTags() {
219+
filterTags.value = JSON.parse(localStorage.getItem(FILTER_TAG_STORAGE_KEY) || '[]');
220+
sharedFilterTags.value = JSON.parse(localStorage.getItem(SHARED_FILTER_TAG_STORAGE_KEY) || '[]');
221+
222+
}
223+
207224
return {
208225
annotationState,
209226
creationType,
@@ -264,5 +281,9 @@ export default function useState() {
264281
loadReviewerMaterials,
265282
viewMaskOverlay,
266283
maskOverlayOpacity,
284+
filterTags,
285+
sharedFilterTags,
286+
saveFilterTags,
287+
loadFilterTags,
267288
};
268289
}

client/src/views/Recordings.vue

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export default defineComponent({
4343
showSubmittedRecordings,
4444
myRecordingsDisplay,
4545
sharedRecordingsDisplay,
46+
filterTags,
47+
sharedFilterTags,
48+
saveFilterTags,
4649
} = useState();
4750
const editingRecording: Ref<EditingRecording | null> = ref(null);
4851
let intervalRef: number | null = null;
@@ -183,8 +186,6 @@ export default defineComponent({
183186
recordingTagList.value = tags.data;
184187
};
185188
186-
const filterTags: Ref<string[]> = ref([]);
187-
const sharedFilterTags: Ref<string[]> = ref([]);
188189
const recordingTagOptions = computed(() =>
189190
recordingTagList.value.map((t) => t.text).filter(Boolean)
190191
);
@@ -198,7 +199,7 @@ export default defineComponent({
198199
}
199200
return userAnnotations.length ? 0 : -1;
200201
}
201-
202+
202203
203204
function currentUserSubmissionLabel(recording: Recording) {
204205
const userSubmittedAnnotation = recording.fileAnnotations.find((annotation: FileAnnotation) => (
@@ -216,7 +217,7 @@ export default defineComponent({
216217
if (showSubmittedRecordings.value) {
217218
headers.value.push(myLabelHeader);
218219
sharedHeaders.value.push(myLabelHeader);
219-
}
220+
}
220221
}
221222
}
222223
@@ -261,8 +262,22 @@ export default defineComponent({
261262
await fetchSharedRecordings({ page: 1, itemsPerPage: 20 });
262263
});
263264
264-
watch(filterTags, () => fetchMyRecordings(lastMyOptions.value), { deep: true });
265-
watch(sharedFilterTags, () => fetchSharedRecordings(lastSharedOptions.value), { deep: true });
265+
watch(
266+
filterTags,
267+
() => {
268+
fetchMyRecordings(lastMyOptions.value);
269+
saveFilterTags();
270+
},
271+
{ deep: true }
272+
);
273+
watch(
274+
sharedFilterTags,
275+
() => {
276+
fetchSharedRecordings(lastSharedOptions.value);
277+
saveFilterTags();
278+
},
279+
{ deep: true }
280+
);
266281
267282
const uploadDone = () => {
268283
uploadDialog.value = false;
@@ -673,6 +688,19 @@ export default defineComponent({
673688
{{ item.name }}
674689
</router-link>
675690
</template>
691+
692+
<template #item.tag_text="{ item }">
693+
<span v-if="item.tags_text">
694+
<v-chip
695+
v-for="tag in item.tags_text"
696+
:key="tag"
697+
size="small"
698+
>
699+
{{ tag }}
700+
</v-chip>
701+
</span>
702+
</template>
703+
676704
<template #item.recorded_date="{ item }">
677705
{{ item.recorded_date }} {{ item.recorded_time }}
678706
</template>

client/src/views/Spectrogram.vue

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ export default defineComponent({
8787
clearContours,
8888
currentRecordingId,
8989
viewMaskOverlay,
90+
filterTags,
91+
sharedFilterTags,
9092
} = useState();
9193
const {
9294
clearPulseMetadata,
@@ -139,6 +141,8 @@ export default defineComponent({
139141
}
140142
};
141143
144+
const combinedTags = computed(() => Array.from (new Set([...filterTags.value, ...sharedFilterTags.value])));
145+
142146
const loading = ref(false);
143147
const spectrogramData: Ref<Spectrogram | null> = ref(null);
144148
const loadData = async () => {
@@ -219,9 +223,11 @@ export default defineComponent({
219223
220224
if (configuration.value.mark_annotations_completed_enabled) {
221225
try {
226+
const tags = Array.from(new Set([...filterTags.value, ...sharedFilterTags.value]));
222227
const neighborsRes = await getUnsubmittedNeighbors(parseInt(props.id, 10), {
223228
sort_by: 'created',
224229
sort_direction: 'desc',
230+
tags: tags,
225231
});
226232
nextUnsubmittedId.value = neighborsRes.data.next_id;
227233
previousUnsubmittedId.value = neighborsRes.data.previous_id;
@@ -378,6 +384,7 @@ export default defineComponent({
378384
fixedAxes,
379385
toggleFixedAxes,
380386
contoursLoading,
387+
combinedTags,
381388
// Other user selection
382389
otherUserAnnotations,
383390
sequenceAnnotations,
@@ -674,42 +681,64 @@ export default defineComponent({
674681
<v-card>
675682
<v-card-title>
676683
<v-row dense>
677-
<v-spacer />
678-
<v-tooltip bottom>
679-
<template #activator="{ props: subProps }">
680-
<v-btn
681-
v-bind="subProps"
682-
:variant="sideTab === 'recordings' ? 'flat' : 'outlined'"
683-
:color="sideTab === 'recordings' ? 'primary' : ''"
684-
class="mx-2"
685-
size="small"
686-
@click="sideTab = 'recordings'"
687-
>
688-
Recordings
689-
</v-btn>
690-
</template>
691-
<span>
692-
View Recordings in sideTab
693-
</span>
694-
</v-tooltip>
695-
<v-tooltip bottom>
696-
<template #activator="{ props: subProps }">
697-
<v-btn
698-
v-bind="subProps"
699-
:variant="sideTab === 'annotations' ? 'flat' : 'outlined'"
700-
:color="sideTab === 'annotations' ? 'primary' : ''"
701-
class="mx-2"
702-
size="small"
703-
@click="sideTab = 'annotations'"
684+
<v-col cols="2">
685+
<v-tooltip v-if="combinedTags.length">
686+
<template #activator="{ props: subProps }">
687+
<v-icon v-bind="subProps">
688+
mdi-filter
689+
</v-icon>
690+
</template>
691+
Filtering by:
692+
<v-chip
693+
v-for="tag in combinedTags"
694+
:key="tag"
704695
>
705-
Annotations
706-
</v-btn>
707-
</template>
708-
<span>
709-
View Annotations in sideTab
710-
</span>
711-
</v-tooltip>
712-
<v-spacer />
696+
{{ tag }}
697+
</v-chip>
698+
</v-tooltip>
699+
<v-spacer v-else />
700+
</v-col>
701+
<v-col cols="4">
702+
<v-tooltip bottom>
703+
<template #activator="{ props: subProps }">
704+
<v-btn
705+
v-bind="subProps"
706+
:variant="sideTab === 'recordings' ? 'flat' : 'outlined'"
707+
:color="sideTab === 'recordings' ? 'primary' : ''"
708+
class="mx-2"
709+
size="small"
710+
@click="sideTab = 'recordings'"
711+
>
712+
Recordings
713+
</v-btn>
714+
</template>
715+
<span>
716+
View Recordings in sideTab
717+
</span>
718+
</v-tooltip>
719+
</v-col>
720+
<v-col cols="4">
721+
<v-tooltip bottom>
722+
<template #activator="{ props: subProps }">
723+
<v-btn
724+
v-bind="subProps"
725+
:variant="sideTab === 'annotations' ? 'flat' : 'outlined'"
726+
:color="sideTab === 'annotations' ? 'primary' : ''"
727+
class="mx-2"
728+
size="small"
729+
@click="sideTab = 'annotations'"
730+
>
731+
Annotations
732+
</v-btn>
733+
</template>
734+
<span>
735+
View Annotations in sideTab
736+
</span>
737+
</v-tooltip>
738+
</v-col>
739+
<v-col>
740+
<v-spacer />
741+
</v-col>
713742
</v-row>
714743
</v-card-title>
715744
<v-card-text class="pa-0">

0 commit comments

Comments
 (0)