Commit f86ac7f5 authored by Yoran Hillion's avatar Yoran Hillion Committed by Jean Rabreau
Browse files

feat: Adds set search in simple search for authenticated users

parent fe7acd6d
......@@ -70,6 +70,8 @@ export const en_US = {
label: 'Search',
title: 'Search',
results: 'Results',
sortOptions: "Sort options",
relevance: "Relevance",
},
dashboard:{
label: 'Dashboard',
......
......@@ -76,6 +76,8 @@ export const fr_FR = {
label: 'Recherche',
title: 'Rechercher',
results: 'Résultats de la recherche',
sortOptions: "Options de tri",
relevance: "Pertinence",
},
dashboard:{
label: 'Tableau de bord',
......@@ -609,7 +611,7 @@ export const fr_FR = {
},
publisher: "Éditeur",
template: "Modèle de métadonnées",
count: "Aucun ensemble | {count} Ensemble | {count} Ensembles",
count: "Aucun ensemble | {count} ensemble | {count} ensembles",
label: "Ensemble",
plural: "Ensembles",
create: "Nouvel ensemble",
......
......@@ -3,33 +3,89 @@
<h2>{{ $t('search.title') }}</h2>
<v-divider />
<v-text-field
:value="query"
v-model="query"
:label="$t('search.label')"
prepend-inner-icon="mdi-magnify"
@change="search"
@change="onSearch"
/>
<v-data-table
:items="results"
>
<template #item="{ item }">
<tr>
<div class="d-flex pa-2">
<avatar
:name="item.name"
:image="item.thumbnail"
class="mr-4"
/>
<div class="d-flex flex-column">
<div class="font-weight-medium">
<router-link :to="item.to">{{ item.highlight.name || item.name }}</router-link>
</div>
<div class="text--secondary" v-html="item.highlight.description.join('[...]') || item.description">
<v-tabs v-model="tab">
<v-tab
v-for="tab in tabs"
:key="tab.id"
>
{{ tab.label }}<v-chip class="ml-1" x-small>{{ tab.serverItemsLength }}</v-chip>
</v-tab>
</v-tabs>
<v-divider />
<v-tabs-items v-model="tab">
<v-tab-item
v-for="tab in tabs"
:key="tab.id"
eager
>
<v-toolbar flat>
<v-select
v-model="tab.sort"
:items="sortItems"
item-text="label"
item-value="value"
:label="$t('search.sortOptions')"
hide-details
>
<template #append-outer>
<v-btn
icon
small
@click="tab.isDescending = !tab.isDescending"
>
<v-icon>{{ tab.isDescending ? 'mdi-sort-descending' : 'mdi-sort-ascending' }}</v-icon>
</v-btn>
</template>
</v-select>
</v-toolbar>
<v-divider />
<v-data-table
:items="tab.results"
:footer-props="{ itemsPerPageOptions: [2, 5, 10, -1] }"
:options.sync="tab.options"
:sort-by.sync="tab.sort"
:sort-desc="tab.isDescending"
:server-items-length="tab.serverItemsLength"
>
<template #item="{ item }">
<tr>
<v-card>
<div class="d-flex">
<avatar
:name="item.name"
:image="item.thumbnail"
class="ml-4 mt-4"
/>
<div class="d-flex flex-column">
<v-card-title>
<router-link :to="item.to">{{ item.name }}</router-link>
</v-card-title>
<v-card-subtitle class="pb-2">
<div>
<span
v-for="(subtitle, index) in item.subtitles"
:key="index"
>
<span v-if="index"> - </span>
{{ subtitle }}
</span>
</div>
</v-card-subtitle>
<v-card-text v-html="item.highlight.description ? item.highlight.description.join('[...]') : item.description">
</v-card-text>
</div>
</div>
</div>
</div>
</tr>
</template>
</v-data-table>
</v-card>
</tr>
</template>
</v-data-table>
</v-tab-item>
</v-tabs-items>
</v-container>
</template>
......@@ -45,70 +101,128 @@ export default {
mixins: [
TextHelpersMixin,
],
props: {
query: {
type: String,
required: false,
default: '',
},
},
components: {
Avatar,
},
data: function() {
return {
apiResults: [],
headers: [
{
value: 'thumbnail',
text: 'Thumbnail',
align: 'left',
sortable: false,
query: '',
tab: undefined,
tabsRoot: [ 'project', 'set' ],
tabs: {
project: {
id: 'project',
label: this.$t('project.plural'),
options: {},
serverItemsLength: 0,
sort: 'score',
isDescending: true,
results: [],
},
{
value: 'name',
text: 'Name',
align: 'left',
sortable: true,
set: {
id: 'set',
label: this.$t('set.plural'),
options: {},
serverItemsLength: 0,
sort: 'score',
isDescending: true,
results: [],
},
],
},
sortOptionsRoot: [ 'score', 'title' ],
sortOptions: {
score: { label: this.$t('search.relevance'), value: 'score' },
title: {},
},
};
},
computed: {
...mapState('contrib', ['isLogged']),
results() {
return this.apiResults.map((result) => ({
axios() {
return this.isLogged ? authority : publicAxios;
},
projectOptions() {
return this.tabs.project.options;
},
setOptions() {
return this.tabs.set.options;
},
sortItems() {
return this.sortOptionsRoot.map((sortOptionId) => this.sortOptions[sortOptionId]);
},
},
watch: {
projectOptions: {
handler: function() {
this.search('project');
},
deep: true,
},
setOptions: {
handler: function() {
this.search('set');
},
deep: true,
},
tab: function(value) {
if (value === 0) {
this.sortOptions.title.label = this.$t('form.field.name');
this.sortOptions.title.value = 'name';
} else {
this.sortOptions.title.label = this.$t('form.field.title');
this.sortOptions.title.value='title';
}
},
},
methods: {
formatResults(results, mode) {
const that = this;
return results.map((result) => ({
id: result.id,
name: this.textTruncate(result.title || result.name, 50),
subtitles: function() {
let subtitles;
if (mode === 'project') {
const managers = result.managers.map(m => m.name).join(', ');
subtitles = [
`${that.$t('project.subtitles.managers', { managers, label: that.$tc('project.managers', result.managers.length) })}`,
`${that.$tc('set.count', result.setsCount)}`,
`${that.$tc('item.count', result.itemsCount)}`,
];
} else if (mode === 'set') {
subtitles = [
`${that.$t('item.fields.creator.label')} : ${result.creator.name}`,
`${that.$tc('item.count', result.itemsCount)}`,
];
}
return subtitles;
}(),
description: this.textTruncate(this.stripHtml(result.description), 300),
thumbnail: result?.thumbnails?.s || null,
to: { name: 'projectPublic', params: { projectId: result.id } },
thumbnail: result.thumbnail || null,
to: { name: `${mode}Public`, params: { [`${mode}Id`]: result.id } },
highlight: result.highlight,
}));
},
},
methods: {
search(query) {
console.log('Searching...');
console.log(query);
const axios = this.isLogged ? authority : publicAxios;
axios.get(`project_search/?query=${query}`)
search(mode) {
const query = this.query || this.$route.params.query;
const pageSize = this.tabs[`${mode}`].options.itemsPerPage;
const page = this.tabs[`${mode}`].options.page;
const ordering = `${this.tabs[`${mode}`].isDescending ? '-' : ''}${this.tabs[`${mode}`].sort}`;
return this.axios.get(`${mode}_search/?query=${query}&page_size=${pageSize}&page=${page}&ordering=${ordering}`)
.then((response) => {
console.log('Search results received');
console.log(response);
this.apiResults = response.data.results;
console.log(this.apiResults);
this.tabs[`${mode}`].results = this.formatResults(response.data.results, mode);
this.tabs[`${mode}`].serverItemsLength = response.data.count;
}).catch((error) => {
console.log('Search error');
console.log(error);
});
},
onSearch() {
this.tabsRoot.forEach((tab) => this.search(tab));
},
},
beforeRouteEnter(to, from, next) {
next((vm) => {
console.log(to);
const { query } = to.params;
if (query) vm.search(query);
if (query) vm.query = query;
});
},
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment