diff --git a/src/components/Projects/DropdownMenuItem.vue b/src/components/Projects/DropdownMenuItem.vue index ca14155ddc25bc5ebab21572e8638037d0f29bd5..8c16b6312e8767cce9cbff2a6f46d13111cc18d7 100644 --- a/src/components/Projects/DropdownMenuItem.vue +++ b/src/components/Projects/DropdownMenuItem.vue @@ -19,7 +19,10 @@ @remove="remove" @close="close" > - <template slot="option" slot-scope="props"> + <template + slot="option" + slot-scope="props" + > <span :title="props.option.label">{{ props.option.label }}</span> </template> <template diff --git a/src/components/Projects/ProjectsMenu.vue b/src/components/Projects/ProjectsMenu.vue index 191bbf9ddc2480f66c7cafd607f995001da35a1d..3370be89e77c7a6a5bd7fedba6ec4d1ca3f32079 100644 --- a/src/components/Projects/ProjectsMenu.vue +++ b/src/components/Projects/ProjectsMenu.vue @@ -1,6 +1,6 @@ <template> <div - v-if="displayedClassicFilters || displayedAttributeFilters" + v-if="chunkedNsortedFilters" id="filters-container" class="margin-bottom" > @@ -21,11 +21,12 @@ </div> <div :class="['full-width', 'filters', { 'hidden': displayFilters }]"> <div - v-if="displayedClassicFilters.length > 0" + v-for="(chunkedFilters, index) in chunkedNsortedFilters" + :key="index" class="ui menu filter-row" > <div - v-for="filter in displayedClassicFilters" + v-for="filter in chunkedFilters" :key="filter.name" class="item" > @@ -37,31 +38,16 @@ v-on="$listeners" /> <DropdownMenuItem - v-else + v-else-if="!filter.id" :options="filter.options" v-on="$listeners" /> - </div> - </div> - <!-- Display several rows if more than 4 project attributes --> - <div - v-for="(groupedAttributes, index) in displayedAttributeFilters" - :key="index" - class="ui menu filter-row" - > - <div - v-for="attribute in groupedAttributes" - :key="attribute.id" - class="item" - > - <label> - {{ attribute.label }} - </label> <DropdownMenuItem - :options="attribute.options" - :multiple="attribute.field_type.includes('list')" - :current-selection="attributesFilter[attribute.id]" - :default-filter="attribute.default_filter_enabled ? attribute.default_filter_value : null" + v-else + :options="filter.options" + :multiple="filter.field_type.includes('list')" + :current-selection="attributesFilter[filter.id]" + :default-filter="filter.default_filter_enabled ? filter.default_filter_value : null" @filter="updateAttributeFilter" @remove="removeAttributeFilter" /> @@ -171,7 +157,7 @@ export default { displayedClassicFilters() { const projectFilters = this.configuration.VUE_APP_PROJECT_FILTERS.split(','); // Filter filters to be displayed according to configuration and process filters - const processedFilters = this.classicFilters.filter(filter => projectFilters.includes(filter.name)) + return this.classicFilters.filter(filter => projectFilters.includes(filter.name)) .map(filter => { if (filter.options) { // if user is not connected display its user access level corresponding to anonymous user @@ -194,8 +180,6 @@ export default { return filter; } }); - - return processedFilters; }, /** * Processes project attributes to prepare them for display, adjusting the options based on the attribute type. @@ -207,7 +191,7 @@ export default { */ displayedAttributeFilters() { // Filter and process attributes - const processedAttributes = this.projectAttributes.filter(attribute => attribute.display_filter) + return this.projectAttributes.filter(attribute => attribute.display_filter) .map(attribute => { // Format the options to be displayed by dropdowns const options = this.generateFilterOptions(attribute); @@ -219,9 +203,19 @@ export default { }); return { ...attribute, options }; }); - - // Chunk the processed attributes into arrays of up to 4 elements - return this.chunkArray(processedAttributes, 4); + }, + /** + * Merge all filters and place the search filters at the end of the array + * Then chunks the array into rows of 4 filters to display each chunk in a row + */ + chunkedNsortedFilters() { + const allFilters = [...this.displayedClassicFilters, ...this.displayedAttributeFilters]; + const sortedFilters = [ + ...allFilters.filter(el => el.name !== 'search'), + ...allFilters.filter(el => el.name === 'search'), + ]; + // Chunk the filters into arrays of up to 4 elements + return this.chunkArray(sortedFilters, 4); }, }, @@ -293,7 +287,7 @@ export default { * Handles both single-choice and multi-choice attribute types. * @param {Object} newFilter - The new filter to be added, containing the attribute key and value. */ - updateAttributeFilter({ value, filter }) { + updateAttributeFilter({ filter, value }) { // Retrieve the attribute type information to determine how to handle the update const attribute = this.getProjectAttribute(filter); // Check if the attribute allows multiple selections @@ -326,10 +320,10 @@ export default { * Particularly useful for multi-choice attributes where individual values can be deselected. * @param {Object} removedFilter - The filter to be removed, containing the attribute key and value. */ - removeAttributeFilter({ value, filter }) { + removeAttributeFilter({ filter, value }) { // Retrieve attribute information to determine if it's a multi-choice attribute const attribute = this.getProjectAttribute(filter); - const isMultiChoice = attribute.field_type === 'multi_choices_list'; + const isMultiChoice = attribute.field_type.includes('list'); if (isMultiChoice) { // For multi-choice attributes, convert the current filter value to an array for manipulation