diff --git a/src/assets/app.scss b/src/assets/app.scss index d911fa09dfdb05a51ce09a165d8d09367b59f58e..d13430856a6cadfbc1c0076601efe78674263bf1 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -71,3 +71,12 @@ h3 { ----padding-right: 1rem; } } + +.checkbox .checkbox-label { + ----label--font-size: 1rem; + margin-bottom: 0.2rem; + &:before { + ----border-radius: 4px; + ----margin-right: 0.5rem; + } +} diff --git a/src/components/Workflows.vue b/src/components/Workflows.vue index e830b1f0de2b52890e8bc7b530dd882f193bc848..3cbfd1a54cbcc04daeecb2cd10c15033aa6bf6d1 100644 --- a/src/components/Workflows.vue +++ b/src/components/Workflows.vue @@ -1,14 +1,20 @@ <template> - <div class="_margin-bottom:3"> + <div class="_display:flex _margin-bottom:3"> <!-- <SelectButton v-model="selectedOption" :options="options" optionLabel="name"></SelectButton>--> <i-button-group> <i-button color="primary" size="lg" :outline="!isList" @click="selectedOption = options[0]">{{options[0].name}}</i-button> <i-button color="primary" size="lg" :outline="!isTable" @click="selectedOption = options[1]">{{options[1].name}}</i-button> </i-button-group> + <MultiFilter + class="_margin-left:auto" + :amount-label="$t('datasets_selected')" + v-model="datasetsFilterOptions" + @update:model-value="onChangeDatasetFilter" + /> </div> <div v-if="selectedOption"> - <WorkflowsList v-if="selectedOption.value === 'list'" :data="data" :defs="defs" /> - <WorkflowsTable v-else :data="data" :defs="defs" /> + <WorkflowsList v-if="selectedOption.value === 'list'" :data="filteredData" :defs="defs" /> + <WorkflowsTable v-else :data="filteredData" :defs="defs" /> </div> </template> @@ -21,10 +27,12 @@ import { useI18n } from "vue-i18n"; import { setEvalColors } from "@/helpers/eval-colors"; import { store } from "@/helpers/store"; + import MultiFilter from "@/components/workflows/MultiFilter.vue"; const { t } = useI18n(); const data = ref([]); + const filteredData = ref([]); const defs = ref({}); const router = useRouter(); const route = useRoute(); @@ -34,7 +42,13 @@ { name: t('table'), value: 'table' } ]); const selectedOption = ref(null); + const datasetsFilterOptions = ref([]); + const onChangeDatasetFilter = (value) => { + value = value.filter(({ selected }) => !!(selected)); + filteredData.value = data.value + .filter(item => value.find(({ id }) => item.metadata.gt_workspace['@id'] === id)); + }; watch(selectedOption, ({ value }) => { router.push({ query: { view: value } }); @@ -56,6 +70,22 @@ data.value = await api.getWorkflows(); defs.value = await api.getEvalDefinitions(); + filteredData.value = data.value; + + const datasetsMap = data.value + .filter(item => !!(item.metadata.gt_workspace)) + .reduce((acc, cur) => { + const gtWorkspaceId = cur.metadata.gt_workspace['@id']; + acc[gtWorkspaceId] = cur.metadata.gt_workspace.label; + return acc; + }, {}); + + datasetsFilterOptions.value = Object.keys(datasetsMap).map(id => ({ + id, + label: datasetsMap[id], + selected: true + })); + setEvalColors(data.value); const filtered = options.value.filter((option) => { diff --git a/src/components/workflows/MultiFilter.vue b/src/components/workflows/MultiFilter.vue new file mode 100644 index 0000000000000000000000000000000000000000..2c5735ee69f1620f35e8f4cd561ea0097d01b593 --- /dev/null +++ b/src/components/workflows/MultiFilter.vue @@ -0,0 +1,56 @@ +<template> + <div class="_display:flex _align-items:center"> + <div class="_font-weight:bold">{{ amount }}</div> + <i-dropdown class="_margin-left:1" placement="bottom-end"> + <i-button>{{ $t('change') }}</i-button> + <template #body> + <div class="options-container _padding-x:2"> + <i-checkbox v-model="allSelected" @update:modelValue="onSelectAll">{{ $t('select_all') }}</i-checkbox> + <i-checkbox v-model="option.selected" @update:modelValue="onChange" v-for="option in filteredOptions" :key="option.id">{{ option.label }}</i-checkbox> + </div> + </template> + </i-dropdown> + </div> +</template> + +<script setup> +import { computed, ref, watch } from "vue"; +import { useI18n } from "vue-i18n"; + +const { t } = useI18n(); +const props = defineProps(['amount-label', 'modelValue']); +const emit = defineEmits(['update:modelValue']); + +const totalAmount = ref(0); +const filteredOptions = ref([]); +const allSelected = ref(true); + +const amount = computed(() => { + return filteredOptions.value.filter(({ selected }) => !!(selected)).length + ` ${t('of')} ` + totalAmount.value + ' ' + props.amountLabel; +}); + +watch(() => props.modelValue, (value) => { + totalAmount.value = value.length; + filteredOptions.value = value.map(({ id, label, selected = false }) => ({ + id, label, selected + })); +}, { immediate: true }); + +const onChange = () => { + allSelected.value = filteredOptions.value.filter(({ selected }) => !(selected)).length === 0; + emit('update:modelValue', filteredOptions.value); +}; + +const onSelectAll = (isChecked) => { + filteredOptions.value.forEach((option, i) => filteredOptions.value[i].selected = isChecked); + emit('update:modelValue', filteredOptions.value); +}; + +</script> + +<style scoped> +.options-container { + max-height: 30vh; + overflow: auto; +} +</style> diff --git a/src/components/workflows/WorkflowsList.vue b/src/components/workflows/WorkflowsList.vue index 91c89e86f964c1a5aa49633672219b47f04e675d..5c21db454a599e8ae43adc8913ebcbd6bbe9fb1a 100644 --- a/src/components/workflows/WorkflowsList.vue +++ b/src/components/workflows/WorkflowsList.vue @@ -268,11 +268,10 @@ const shortenCER = (value) => { return Math.round(value * 1000) / 1000; }; - onMounted(() => { - setEvals(props.data); - setListData(props.data); - }); - +onMounted(() => { + setEvals(props.data); + setListData(props.data); +}); watch(() => props.data, () => { setEvals(props.data); diff --git a/src/locales/de.json b/src/locales/de.json index d6f36bed97e9be41103e7c303199d532f57bbb3c..2e740ebb606414a009e13a51b757af44b5f00e35 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -28,5 +28,9 @@ "cer_max_desc": "CER Max absteigend", "no_table_data": "Keine Tabellendaten verfügbar", "workflow_steps": "Workflowschritte", - "external_repo_url": "Externer Link zum Repository" + "external_repo_url": "Externer Link zum Repository", + "change": "Ändern", + "datasets_selected": "Datasets ausgewählt", + "of": "von", + "select_all": "Alle auswählen" } diff --git a/src/locales/en.json b/src/locales/en.json index 53a62d192405d787c0cf23c3c599eae286d7b54d..4bc3ad76df1c5c1b2d6b5d46894107fa3b63929d 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -22,5 +22,9 @@ "cer_max_desc": "CER Max descending", "no_table_data": "No table data available", "workflow_steps": "Workflow steps", - "external_repo_url": "External link to the repository" + "external_repo_url": "External link to the repository", + "change": "Change", + "datasets_selected": "datasets selected", + "of": "of", + "select_all": "Select all" }