Skip to content

Commit

Permalink
feat: add filters for gt labelling and gt script-type (#88)
Browse files Browse the repository at this point in the history
* feat: filter by workflow and processor

* feat: filter by date range

* feat: implement multi-selectable workflow steps filtering

* fix: make only related workflows visible while filtering by processors

* fix: set all checkboxes of processor filter to selected on page load

* ref: highlight selected processors

* fix: refactor to own component and prepare visual filtering

* fix: show filter also when no data is selected

* fix: workflow filter label

* feat: hide workflow when neither workflow or processor in workflow are selected

* refactor: remove unused imports/vars, style

* fix: remove search from workflow filter

* feat: change date range dropdown to multiselect

* refactor: change order

* feat: add i18n translations

* fix: adjust filter position for smaller screens

* fix: changed faulty imported that failed build

* wip: add label filter

* wip: added label and script-type filter

* fix: adjust styling for all screen sizes

* style: clearer indentation

* fix: readd missing comparision

* style: break filter condition into multiple lines

* docs: add comment explaining the computed ref labellingOptions

* feat: add select all label; refactor to own component

* fix: make color of select all variable

---------

Co-authored-by: amtul.noor <[email protected]>
Co-authored-by: noornoorie <[email protected]>
Co-authored-by: jfrer <[email protected]>
  • Loading branch information
4 people authored Jul 26, 2024
1 parent 4f02e8c commit 65da64d
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 37 deletions.
48 changes: 48 additions & 0 deletions src/components/base/MultiSelect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import MultiSelect from "primevue/multiselect"
import { computed, ref } from 'vue'
import { useI18n } from "vue-i18n"
import type { DropdownOption } from '@/types'
const { t } = useI18n()
const props = defineProps<{
filter?: boolean
allSelectedLabel?: string
options: DropdownOption[]
}>()
const allItemsSelected = ref(true)
const dropdownLabel = computed(() => {
if (allItemsSelected.value) {
return props.allSelectedLabel
}
return undefined
})
</script>
<template>
<MultiSelect
@change="allItemsSelected = $event.value.length === options.length"
:filter="filter?? false"
:selected-items-label="dropdownLabel"
:options="options"
option-label="label"
:pt="{
filterContainer: {
class: { 'ml-20': props.filter }
}
}">
<template #headercheckboxicon="{ allSelected }">
<Icon v-show="allSelected" icon="prime:check" class="p-checkbox-icon h-5 w-5" data-pc-section="headercheckboxicon"/>
<span :class="['ml-[7.5rem] absolute w-20 z-[1001]', allSelected ? 'text-highlight' : 'text-black']">{{ t('select_all') }}</span>
</template>
</MultiSelect>
</template>
<style scoped lang="scss">
.text-highlight {
color: var(--highlight-text-color);
}
</style>
115 changes: 81 additions & 34 deletions src/components/workflows/timeline/TimelineFilters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import filtersStore from "@/store/filters-store"
import workflowsStore from "@/store/workflows-store"
import { computed, onMounted, ref, watch } from "vue"
import MultiSelect from "primevue/multiselect"
import type { DropdownOption, GroundTruth } from "@/types"
import { deduplicateStepIds, mapGtId } from '@/helpers/utils'
import { useI18n } from "vue-i18n"
import BaseMultiSelect from "@/components/base/MultiSelect.vue"
const { t } = useI18n()
Expand All @@ -25,26 +25,44 @@ const selectedWorkflows = ref<DropdownOption[]>([])
const workflowStepOptions = ref<DropdownOption[]>([])
const selectedWorkflowSteps = ref<DropdownOption[]>([])
const dateRangeDropdownLabel = computed(() => {
if (dateRangeOptions.value.length === selectedDateRange.value.length) {
return t('filter_by_date_range')
}
return null
/*
Compiles the DropdownOption[] for the labelling filter.
Each gt can have a list of labels, while some have no labelling at all.
The DropdownOption[] is computed by adding all labelling options to a flat list, then making them unique and sorting them.
*/
const labellingOptions = computed(() => {
return [
...new Set(workflowsStore.gt.map(gt =>
Array.isArray(gt.metadata.labelling) && gt.metadata.labelling.length > 0 ? gt.metadata.labelling : [t('no_labelling')]
).flat(1)
)
]
.sort()
.map(value => ({ value, label: value }))
})
const workflowDropdownLabel = computed(() => {
if (workflowOptions.value.length === selectedWorkflows.value.length) {
return t('filter_by_workflow')
}
return null
const selectedLabelling = ref<DropdownOption[]>([])
const scriptTypeOptions = computed(() => {
return [
...new Set(workflowsStore.gt.map(gt =>
gt.metadata["script-type"]
))
]
.sort()
.map(value => ({ value, label: value }))
})
const selectedScriptTypes = ref<DropdownOption[]>([])
const workflowStepDropdownLabel = computed(() => {
if (workflowStepOptions.value.length === selectedWorkflowSteps.value.length) {
return t('filter_by_processor')
}
return null
})
const onLabellingChange = (event: any) => {
selectedLabelling.value = event
selectGTs()
}
const onScriptTypeChange = (event: any) => {
selectedScriptTypes.value = event
selectGTs()
}
const onDateRangeChange = (event: any) => {
selectedDateRange.value = event
Expand All @@ -67,13 +85,29 @@ const selectGTs = () => {
filtersStore.gtTimeline = filtersStore.gt.filter(({ value }) => {
const gt = workflowsStore.getGtById(value)
if(!gt) return false
return hasSomeSelectedProcessor(gt) && hasSomeSelectedDateRange(gt) && hasSomeSelectedWorkflow(gt)
return (
hasSomeSelectedLabelling(gt) &&
hasSomeSelectedScriptType(gt) &&
hasSomeSelectedProcessor(gt) &&
hasSomeSelectedDateRange(gt) &&
hasSomeSelectedWorkflow(gt)
)
})
}
const selectWorkflows = () => {
filtersStore.workflow = selectedWorkflows.value.filter(({ value }) => (workflowhasSomeSelectedWorkflowStep(value)))
}
const hasSomeSelectedLabelling = (gt: GroundTruth) => {
return selectedLabelling.value.some(({ value }) => {
if(!Array.isArray(gt.metadata.labelling) || gt.metadata.labelling.length <= 0) return value === t('no_labelling')
return gt.metadata.labelling?.some(labelling => labelling === value)
})
}
const hasSomeSelectedScriptType = (gt: GroundTruth) => {
return selectedScriptTypes.value.some(({ value }) => value === gt.metadata["script-type"])
}
const hasSomeSelectedProcessor = (gt: GroundTruth) => {
const gtRuns = workflowsStore.getRuns(gt.id)
Expand All @@ -96,7 +130,7 @@ const hasSomeSelectedDateRange = (gt: GroundTruth) => {
const hasSomeSelectedWorkflow = (gt: GroundTruth) => {
const gtRuns = workflowsStore.getRuns(gt.id)
return gtRuns.some((gtRun) => {
return selectedWorkflows.value.findIndex(({ value }) => (value === mapGtId(gtRun.metadata.ocr_workflow.id))) > -1
return selectedWorkflows.value.findIndex(({ value }) => (value === mapGtId(gtRun.metadata.ocr_workflow.id))) > -1
})
}
Expand All @@ -116,44 +150,57 @@ onMounted(() => {
selectedDateRange.value = dateRangeOptions.value
selectedWorkflows.value = workflowOptions.value
selectedWorkflowSteps.value = workflowStepOptions.value
selectedLabelling.value = labellingOptions.value
selectedScriptTypes.value = scriptTypeOptions.value
selectGTs()
selectWorkflows()
})
</script>

<template>
<div class="flex flex-wrap mb-4 justify-start lg:justify-end">
<MultiSelect
<div class="pb-4 lg:pb-6 grid sm:grid-cols-2 gap-4 xl:grid-cols-5 xl:gap-8">
<BaseMultiSelect
v-model="selectedLabelling"
@update:model-value="onLabellingChange($event)"
filter
:max-selected-labels="0"
:options="labellingOptions"
:placeholder="t('select_a_label')"
:all-selected-label="t('filter_by_labelling')"
/>
<BaseMultiSelect
v-model="selectedScriptTypes"
@update:model-value="onScriptTypeChange($event)"
:max-selected-labels="0"
:options="scriptTypeOptions"
:placeholder="t('select_a_script_type')"
:all-selected-label="t('filter_by_script_type')"
/>
<BaseMultiSelect
v-model="selectedDateRange"
@update:model-value="onDateRangeChange($event)"
:max-selected-labels="1"
:options="dateRangeOptions"
optionLabel="label"
:placeholder="t('select_a_date_range')"
:selected-items-label="dateRangeDropdownLabel"
class="mr-4 mb-2 lg:m-0 lg:ml-auto md:w-14rem"
:all-selected-label="t('filter_by_date_range')"
/>
<MultiSelect
<BaseMultiSelect
v-model="selectedWorkflows"
@update:model-value="onWorkflowChange($event)"
:max-selected-labels="1"
:options="workflowOptions"
optionLabel="label"
:placeholder="t('select_a_workflow')"
:selected-items-label="workflowDropdownLabel"
class="mr-4 mb-2 lg:m-0 lg:ml-4 md:w-14rem"
:all-selected-label="t('filter_by_workflow')"
/>
<MultiSelect
<BaseMultiSelect
v-model="selectedWorkflowSteps"
@update:model-value="onWorkflowStepChange($event)"
filter
:max-selected-labels="1"
:options="workflowStepOptions"
optionLabel="label"
:placeholder="t('select_a_processor')"
:selected-items-label="workflowStepDropdownLabel"
class="lg:ml-4 md:w-14rem"
:all-selected-label="t('filter_by_processor')"
/>
</div>

Expand Down
7 changes: 6 additions & 1 deletion src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@
"filter_by_date_range": "Nach Zeitspanne filtern",
"filter_by_workflow": "Nach Workflow filtern",
"filter_by_processor": "Nach Prozessor filtern",
"filter_by_labelling": "Nach Kennzeichnungen filtern",
"filter_by_script_type": "Nach Skript-Typ filtern",
"select_a_date_range": "Zeitraum auswählen",
"select_a_workflow": "Workflow auswählen",
"select_a_processor": "Prozessor auswählen",
Expand All @@ -93,5 +95,8 @@
"metric_desc": "Ausgewählte Metrik (absteigend)",
"metric_asc": "Ausgewählte Metrik (aufsteigend)",
"year_asc": "Zeitraum (ältester - neuster)",
"year_desc": "Zeitraum (neuster - ältester)"
"year_desc": "Zeitraum (neuster - ältester)",
"select_a_label": "Kennzeichnung auswählen",
"select_a_script_type": "Skript-Typ auswählen",
"no_labelling": "Keine Kennzeichnung"
}
7 changes: 6 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
"filter_by_date_range": "Filter by date range",
"filter_by_workflow": "Filter by workflow",
"filter_by_processor": "Filter by processor",
"filter_by_labelling": "Filter by labelling",
"filter_by_script_type": "Filter by script-type",
"select_a_date_range": "Select a date range",
"select_a_workflow": "Select a workflow",
"select_a_processor": "Select a processor",
Expand All @@ -88,5 +90,8 @@
"metric_desc": "Selected metric (descending)",
"metric_asc": "Selected metric (ascending)",
"year_asc": "Time period (oldest - latest)",
"year_desc": "Time period (latest - oldest)"
"year_desc": "Time period (latest - oldest)",
"select_a_label": "Select a label",
"select_a_script_type": "Select a script-type",
"no_labelling": "No labelling"
}
2 changes: 1 addition & 1 deletion src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface GroundTruthMetadata {
count: string,
level: string
},
labelling: string[],
labelling?: string[],
language: string[],
license: {
name: string,
Expand Down

0 comments on commit 65da64d

Please sign in to comment.