Implement filters and JSON building [SCI-5956]

This commit is contained in:
Martin Artnik 2021-08-20 11:01:21 +02:00
parent 0b74f34de7
commit 9a87bad740
14 changed files with 410 additions and 24 deletions

View file

@ -1,12 +1,36 @@
#bmtFilterContainer {
min-width: 300px;
min-width: 422px;
z-index: 100;
label {
font-weight: normal;
}
.form-group {
display: block;
width: 100%;
.form-control,
.form-select {
margin-bottom: 21px;
width: 100%;
}
}
.checkbox-label {
vertical-align: text-bottom;
}
.filter-list-notice {
color: $color-silver-chalice;
padding: 16px;
}
.header {
align-items: center;
border-bottom: $border-tertiary;
display: flex;
padding: .5em 1em;
padding: 0 1em;
.title {
@include font-h2;
@ -16,19 +40,37 @@
.filter-element {
align-items: center;
border-bottom: $border-tertiary;
display: flex;
padding: 15px 52px 15px 15px;
position: relative;
}
.filter-remove {
padding: 0;
position: absolute;
right: 16px;
top: 16px;
.btn {
height: 16px;
padding: 0;
width: 16px;
}
.btn:hover {
background: $color-white;
}
}
.filters-list {
border-top: $border-tertiary;
padding: .5em 1em;
}
.footer {
align-items: center;
border-top: $border-tertiary;
display: flex;
padding: .5em 1em;
.add-filter {
margin-right: auto;

View file

@ -16,6 +16,7 @@
"jsx": true
}
},
"ignorePatterns": ["*.vue", "**/mixins/*.js"],
"rules": {
"import/extensions": "off",
"import/no-unresolved": "off",

View file

@ -3,7 +3,7 @@ import Vue from 'vue/dist/vue.esm';
import FilterContainer from '../../vue/bmt_filter/container.vue';
Vue.use(TurbolinksAdapter);
Vue.prototype.i18n = window.I18n;
window.initBMTFilter = () => {
const app = new Vue({
@ -13,8 +13,5 @@ window.initBMTFilter = () => {
}
});
$('#bmtFilterContainer').on('click', (e) => {
e.preventDefault();
e.stopPropagation();
});
$('#bmtFilterContainer').on('click', (e) => e.stopPropagation());
};

View file

@ -10,7 +10,16 @@
</button>
</div>
<div class="filters-list">
<FilterElement v-for="(filter, index) in filters" :key="filter.id" :filter.sync="filters[index]" @delete:filter="filters.splice(index, 1)"></FilterElement>
<div v-if="filters.length == 0" class="filter-list-notice">
<p class="text-muted"><em>{{ i18n.t('repositories.show.bmt_search.no_filters') }}</em></p>
</div>
<FilterElement
v-for="(filter, index) in filters"
:key="filter.id"
:filter.sync="filters[index]"
@filter:delete="filters.splice(index, 1)"
@filter:update="updateFilter"
/>
</div>
<div class="footer">
<button class="btn btn-light add-filter" @click="addFilter">
@ -31,30 +40,44 @@
name: 'FilterContainer',
data() {
return {
filters: [],
i18n: I18n
filters: []
}
},
props: {
container: Object
},
components: { FilterElement },
computed: {
searchJSON() {
return this.filters.map((f) => f.data);
}
},
methods: {
addFilter: function() {
var id;
addFilter() {
let id;
if (this.filters.length > 0) {
id = this.filters[this.filters.length - 1].id + 1
} else {
id = 1
};
this.filters.push({
id: id
});
this.filters.push({ id: id, data: { type: "fullSequenceFilter" } });
},
clearAllFilters: function() {
this.filters = []
updateFilter(filter) {
this.filters.find((f) => f.id === filter.id).data = filter.data;
},
clearAllFilters() {
this.filters = [];
},
loadFilters(filters) {
this.clearAllFilters();
filters.forEach((filter, index) => {
this.filters.push(
{
id: index,
data: filter
}
);
});
}
}
}

View file

@ -1,20 +1,72 @@
<template>
<div class="filter-element">
<div class="filter-action">
Filter {{ filter.id }}
<div class="form-group filter-action">
<div class="form-select">
<select @change="updateFilter({ type: $event.target.value })" v-model="type">
<option
v-for="type in types"
:key="type.name" :value="type">
{{ i18n.t('repositories.show.bmt_search.filters.types.' + type + '.name') }}
</option>
</select>
</div>
<component :is="type" @filter:updateData="updateFilter" :currentData="filter.data" />
</div>
<div class="filter-remove">
<button class="btn btn-light icon-btn" @click="$emit('delete:filter')">
<button class="btn btn-light icon-btn" @click="$emit('filter:delete')">
<i class="fas fa-times-circle"></i>
</button>
</div>
<hr>
</div>
</template>
<script>
import additionalDataFilter from 'vue/bmt_filter/filters/additionalDataFilter.vue'
import entityTypeFilter from 'vue/bmt_filter/filters/entityTypeFilter.vue'
import monomerTypeFilter from 'vue/bmt_filter/filters/monomerTypeFilter.vue'
import subsequenceFilter from 'vue/bmt_filter/filters/subsequenceFilter.vue'
import variantSequenceFilter from 'vue/bmt_filter/filters/variantSequenceFilter.vue'
import fullSequenceFilter from 'vue/bmt_filter/filters/fullSequenceFilter.vue'
import monomerSubstructureSearchFilter from 'vue/bmt_filter/filters/monomerSubstructureSearchFilter.vue'
export default {
props: {
filter: Object
},
data() {
return {
type: this.filter.data.type,
types: [
'additionalDataFilter',
'entityTypeFilter',
'monomerTypeFilter',
'subsequenceFilter',
'variantSequenceFilter',
'fullSequenceFilter',
'monomerSubstructureSearchFilter'
]
}
},
components: {
additionalDataFilter,
entityTypeFilter,
monomerTypeFilter,
subsequenceFilter,
variantSequenceFilter,
fullSequenceFilter,
monomerSubstructureSearchFilter
},
methods: {
updateFilter(data) {
this.$emit(
'filter:update',
{
id: this.filter.id,
data: data
}
);
}
}
}
</script>

View file

@ -0,0 +1,3 @@
<template>
<h1>TODO: additionalData</h1>
</template>

View file

@ -0,0 +1,25 @@
<template>
<div class="filter-form">
<input
@input="updateFilterData"
class="form-control"
type="text"
name="entityType"
v-model="entityType"
:placeholder="i18n.t('repositories.show.bmt_search.filters.types.entityTypeFilter.placeholder')"
/>
</div>
</template>
<script>
import FilterMixin from 'vue/bmt_filter/mixins/filter.js'
export default {
name: 'entityTypeFilter',
mixins: [FilterMixin],
data() {
return {
entityType: ""
}
}
}
</script>

View file

@ -0,0 +1,42 @@
<template>
<div class="filter-form">
<input
@input="updateFilterData"
class="form-control"
type="text"
name="sequence"
v-model="sequence"
:placeholder="i18n.t('repositories.show.bmt_search.filters.types.fullSequenceFilter.placeholder')"
/>
<div>
<label>
<div class="sci-checkbox-container">
<input
@change="updateFilterData"
class="sci-checkbox"
type="checkbox"
v-model="derivativesIncluded"
/>
<label class="sci-checkbox-label"></label>
</div>
<span class="checkbox-label">
{{ i18n.t('repositories.show.bmt_search.filters.types.fullSequenceFilter.derivatives_included') }}
</span>
</label>
</div>
</div>
</template>
<script>
import FilterMixin from 'vue/bmt_filter/mixins/filter.js'
export default {
name: 'fullSequenceFilter',
mixins: [FilterMixin],
data() {
return {
sequence: "",
derivativesIncluded: false
}
}
}
</script>

View file

@ -0,0 +1,25 @@
<template>
<div class="filter-form">
<input
@input="updateFilterData"
class="form-control"
type="text"
name="structure"
v-model="structure"
:placeholder="i18n.t('repositories.show.bmt_search.filters.types.monomerSubstructureSearchFilter.placeholder')"
/>
</div>
</template>
<script>
import FilterMixin from 'vue/bmt_filter/mixins/filter.js'
export default {
name: 'monomerSubstructureSearchFilter',
mixins: [FilterMixin],
data() {
return {
structure: ""
}
}
}
</script>

View file

@ -0,0 +1,25 @@
<template>
<div class="filter-form">
<input
@input="updateFilterData"
class="form-control"
type="text"
name="monomerType"
v-model="monomerType"
:placeholder="i18n.t('repositories.show.bmt_search.filters.types.monomerTypeFilter.placeholder')"
/>
</div>
</template>
<script>
import FilterMixin from 'vue/bmt_filter/mixins/filter.js'
export default {
name: 'monomerTypeFilter',
mixins: [FilterMixin],
data() {
return {
monomerType: ""
}
}
}
</script>

View file

@ -0,0 +1,42 @@
<template>
<div class="filter-form">
<input
@input="updateFilterData"
class="form-control"
type="text"
name="sequence"
v-model="sequence"
:placeholder="i18n.t('repositories.show.bmt_search.filters.types.subsequenceFilter.placeholder')"
/>
<div>
<label>
<div class="sci-checkbox-container">
<input
@change="updateFilterData"
class="sci-checkbox"
type="checkbox"
v-model="derivativesIncluded"
/>
<label class="sci-checkbox-label"></label>
</div>
<span class="checkbox-label">
{{ i18n.t('repositories.show.bmt_search.filters.types.subsequenceFilter.derivatives_included') }}
</span>
</label>
</div>
</div>
</template>
<script>
import FilterMixin from 'vue/bmt_filter/mixins/filter.js'
export default {
name: 'subsequenceFilter',
mixins: [FilterMixin],
data() {
return {
sequence: "",
derivativesIncluded: false
}
}
}
</script>

View file

@ -0,0 +1,59 @@
<template>
<div class="filter-form">
<input
@input="updateFilterData"
class="form-control"
type="text"
name="sequence"
v-model="sequence"
:placeholder="i18n.t('repositories.show.bmt_search.filters.types.variantSequenceFilter.placeholder')"
/>
<div>
<label>
<div class="row">
<div class="col-md-4">
<label for="distance">{{ i18n.t('repositories.show.bmt_search.filters.types.variantSequenceFilter.distance') }}</label>
<input class="form-control" @input="updateFilterData" type="text" v-model="distance" />
</div>
<div class="col-md-4">
<label>
<input
@change="updateFilterData"
type="radio"
v-model="distanceType"
value="EXACT"
/>
<span>{{ i18n.t('repositories.show.bmt_search.filters.types.variantSequenceFilter.exact') }}</span>
</label>
</div>
<div class="col-md-4">
<label>
<input
@change="updateFilterData"
type="radio"
v-model="distanceType"
value="MAX"
/>
<span>{{ i18n.t('repositories.show.bmt_search.filters.types.variantSequenceFilter.maximum') }}</span>
</label>
</div>
</div>
</label>
</div>
</div>
</template>
<script>
import FilterMixin from 'vue/bmt_filter/mixins/filter.js'
export default {
name: 'variantSequenceFilter',
mixins: [FilterMixin],
data() {
return {
sequence: "",
distance: null,
distanceType: "EXACT"
}
}
}
</script>

View file

@ -0,0 +1,19 @@
export default {
props: {
currentData: Object
},
data() {
return {
type: this.$options.name
}
},
created() {
// load existing filter data
Object.keys(this.currentData).forEach((key) => { this[key] = this.currentData[key] });
},
methods: {
updateFilterData() {
this.$emit('filter:updateData', this.$data);
}
}
}

View file

@ -1369,6 +1369,37 @@ en:
clear_all: "Clear all"
add_filter: "Add filter"
apply: "Apply"
filter: "Filter"
no_filters: "Filter through Chemaxon's database. No active filters are applied at the moment."
filters:
types:
additionalDataFilter:
name: "Additional data"
entityTypeFilter:
name: "Entity type"
placeholder: "Enter entity type"
monomerTypeFilter:
name: "Monomer type"
placeholder: "Enter monomer type"
subsequenceFilter:
name: "Subsequence"
placeholder: "Enter subsequence"
derivatives_included: "Derivatives included"
variantSequenceFilter:
name: "Variant sequence"
placeholder: "Enter variant sequence"
derivatives_included: "Derivatives included"
distance: "Distance"
distance_type: "Distance type"
exact: "Exact"
maximum: "Maximum"
fullSequenceFilter:
name: "Full sequence"
placeholder: "Enter full sequence"
derivatives_included: "Derivatives included"
monomerSubstructureSearchFilter:
name: "Monomer substructure"
placeholder: "Enter substructure"
table:
id: 'ID'
external_id: 'External ID'