Skip to content

Commit

Permalink
Merge pull request #4639 from inception-project/feature/4638-Ability-…
Browse files Browse the repository at this point in the history
…to-filter-annotation-sidebar-by-covered-text

#4638 - Ability to filter annotation sidebar by covered text
  • Loading branch information
reckart authored Mar 17, 2024
2 parents 529f467 + d14b2e5 commit e0d4e72
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import { compareOffsets } from "@inception-project/inception-js-api/src/model/Offsets";
import LabelBadge from "./LabelBadge.svelte";
import SpanText from "./SpanText.svelte";
import { compareSpanText, groupBy, renderLabel, uniqueLabels } from "./Utils";
import { compareSpanText, debounce, filterAnnotations, groupBy, renderLabel, uniqueLabels } from "./Utils";
import { sortByScore, recommendationsFirst } from "./AnnotationBrowserState"
export let ajaxClient: DiamAjax
Expand All @@ -39,6 +39,7 @@
let groupedAnnotations: Record<string, Annotation[]>
let groups: { label: string, collapsed: boolean }[]
let collapsedGroups = new Set<string>()
let filter = '';
$: {
const sortedLabels = [...pinnedGroups, ...uniqueLabels(data).filter(v => !pinnedGroups.includes(v))]
Expand All @@ -54,7 +55,8 @@
(s) => renderLabel(s)
)
for (const items of Object.values(groupedAnnotations)) {
for (let [key, items] of Object.entries(groupedAnnotations)) {
items = filterAnnotations(data, items, filter)
items.sort((a, b) => {
if (a instanceof Span && !(b instanceof Span)) {
return -1;
Expand Down Expand Up @@ -92,6 +94,7 @@
console.error("Unexpected annotation type combination", a, b);
});
groupedAnnotations[key] = items
}
}
Expand Down Expand Up @@ -128,6 +131,13 @@
collapsedGroups.clear()
data = data // Trigger reactive update
}
const updateFilter = debounce(newFilter => { filter = newFilter }, 300);
// Function to handle input changes
function handleFilterChange(event) {
updateFilter(event.target.value)
}
</script>

{#if !data}
Expand All @@ -139,6 +149,9 @@
</div>
</div>
{:else}
<div class="d-flex flex-row flex-wrap">
<input type="text" class="form-control rounded-0" on:input={handleFilterChange} placeholder="Filter"/>
</div>
<div class="d-flex flex-row flex-wrap">
<div class="form-check form-switch mx-2">
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import { compareOffsets } from "@inception-project/inception-js-api/src/model/Offsets";
import LabelBadge from "./LabelBadge.svelte";
import SpanText from "./SpanText.svelte";
import { compareSpanText, groupBy, uniqueLayers } from "./Utils";
import { compareSpanText, debounce, filterAnnotations, getCoveredText, groupBy, uniqueLayers } from "./Utils";
import { sortByScore, recommendationsFirst } from "./AnnotationBrowserState"
export let ajaxClient: DiamAjax;
Expand All @@ -39,6 +39,7 @@
let groupedAnnotations: Record<string, Annotation[]>;
let groups: { layer: Layer, collapsed: boolean }[]
let collapsedGroups = new Set<number>()
let filter = '';
$: {
const sortedLayers = uniqueLayers(data)
Expand All @@ -54,7 +55,8 @@
(s) => s.layer.name
)
for (const items of Object.values(groupedAnnotations)) {
for (let [key, items] of Object.entries(groupedAnnotations)) {
items = filterAnnotations(data, items, filter)
items.sort((a, b) => {
if (a instanceof Span && !(b instanceof Span)) {
return -1;
Expand Down Expand Up @@ -92,6 +94,7 @@
console.error("Unexpected annotation type combination", a, b);
});
groupedAnnotations[key] = items
}
}
Expand Down Expand Up @@ -128,6 +131,13 @@
collapsedGroups.clear()
data = data // Trigger reactive update
}
const updateFilter = debounce(newFilter => { filter = newFilter }, 300);
// Function to handle input changes
function handleFilterChange(event) {
updateFilter(event.target.value)
}
</script>

{#if !data}
Expand All @@ -139,6 +149,9 @@
</div>
</div>
{:else}
<div class="d-flex flex-row flex-wrap">
<input type="text" class="form-control rounded-0" on:input={handleFilterChange} placeholder="Filter"/>
</div>
<div class="d-flex flex-row flex-wrap">
<div class="form-check form-switch mx-2">
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import LabelBadge from "./LabelBadge.svelte";
import SpanText from "./SpanText.svelte";
import {
debounce,
groupRelationsByPosition,
groupSpansByPosition,
uniqueOffsets,
Expand All @@ -40,10 +41,18 @@
let groupedSpans: Record<string, Span[]>;
let groupedRelations: Record<string, Relation[]>;
let sortedSpanOffsets: Offsets[];
let filter = '';
$: groupedSpans = groupSpansByPosition(data);
$: groupedRelations = groupRelationsByPosition(data);
$: sortedSpanOffsets = uniqueOffsets(data);
$: {
sortedSpanOffsets = uniqueOffsets(data);
const normalizedFilter = filter.replace(/\s+/g, ' ').toLowerCase()
sortedSpanOffsets = sortedSpanOffsets.filter(offset => {
let coveredText = data.text?.substring(offset[0], offset[1]) || '';
return coveredText.replace(/\s+/g, ' ').toLowerCase().includes(normalizedFilter)
})
}
function scrollToSpan(span: Span) {
ajaxClient.scrollTo({ id: span.vid, offset: span.offsets[0] });
Expand All @@ -60,6 +69,13 @@
function mouseOutAnnotation(event: MouseEvent, annotation: Annotation) {
event.target.dispatchEvent(new AnnotationOutEvent(annotation, event));
}
const updateFilter = debounce(newFilter => { filter = newFilter }, 300);
// Function to handle input changes
function handleFilterChange(event) {
updateFilter(event.target.value)
}
</script>

{#if !data}
Expand All @@ -71,6 +87,9 @@
</div>
</div>
{:else}
<div class="d-flex flex-row flex-wrap">
<input type="text" class="form-control rounded-0" on:input={handleFilterChange} placeholder="Filter"/>
</div>
<div class="flex-content fit-child-snug">
{#if sortedSpanOffsets || sortedSpanOffsets?.length}
<ul class="scrolling flex-content list-group list-group-flush">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
</script>

<div class="flex-content flex-v-container" bind:this={element}>
<select bind:value={$groupingMode} class="form-select">
<select bind:value={$groupingMode} class="form-select rounded-0">
{#each Object.keys(modes) as value}<option {value}
>{modes[value]}</option
>{/each}
Expand Down
32 changes: 32 additions & 0 deletions inception/inception-diam-editor/src/main/ts/src/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,27 @@ export function groupSpansByLabel (data: AnnotatedText): Record<string, Span[]>
return groups
}

export function filterAnnotations (data: AnnotatedText, items: Annotation[], filter: string) {
const normalizedFilter = filter.toLowerCase().replace(/\s+/g, ' ')

if (!normalizedFilter) return items

return items.filter(item => {
if (item instanceof Relation) {
return getCoveredText(data, item.arguments[0].target).replace(/\s+/g, ' ').toLowerCase().includes(normalizedFilter)
}
if (item instanceof Span) {
return getCoveredText(data, item).replace(/\s+/g, ' ').toLowerCase().includes(normalizedFilter)
}
return false
})
}

export function getCoveredText (data: AnnotatedText, a: Span | undefined): string {
if (a === undefined) return ''
return data.text?.substring(a.offsets[0][0], a.offsets[0][1]) || ''
}

export function compareSpanText (data: AnnotatedText, a: Span, b: Span): number {
const textA = data.text?.substring(a.offsets[0][0], a.offsets[0][1]) || ''
const textB = data.text?.substring(b.offsets[0][0], b.offsets[0][1]) || ''
Expand Down Expand Up @@ -157,3 +178,14 @@ export function highlightClasses (vid: VID, data: AnnotatedText): string {
}
return classes.join(' ')
}

export function debounce (func, delay: number) {
let timeoutId

return function (...args) {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
func.apply(this, args)
}, delay)
}
}

0 comments on commit e0d4e72

Please sign in to comment.