Merge pull request #7538 from aignatov-bio/ai-sci-10681-small-fixes-global-search

Small fixes for global search [SCI-10681][SCI-10679]
This commit is contained in:
aignatov-bio 2024-05-08 14:57:14 +02:00 committed by GitHub
commit 24d76f0321
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 108 additions and 24 deletions

View file

@ -8,12 +8,36 @@
</div>
</div>
<div class="bg-white rounded p-4 flex gap-2.5 z-10 items-center mb-4 sticky top-0">
<div class="left-icon sci-input-container-v2 w-72 input-sm"
:title="i18n.t('nav.search')" :class="{'error': invalidQuery}">
<input ref="searchField" type="text" class="!pr-9" :value="localQuery" @change="changeQuery" :placeholder="i18n.t('nav.search')"/>
<i class="sn-icon sn-icon-search"></i>
<i v-if="localQuery.length > 0" class="sn-icon cursor-pointer sn-icon-close absolute right-0 -top-0.5" @click="localQuery = ''"></i>
</div>
<GeneralDropdown ref="historyContainer" :canOpen="canOpenHistory" :fieldOnlyOpen="true" >
<template v-slot:field>
<div class="left-icon sci-input-container-v2 w-72 input-sm"
:title="i18n.t('nav.search')" :class="{'error': invalidQuery}">
<input ref="searchField"
type="text"
class="!pr-9"
:value="localQuery"
@change="changeQuery"
@keydown.enter="changeQuery"
@blur="changeQuery"
:placeholder="i18n.t('nav.search')"
/>
<i class="sn-icon sn-icon-search"></i>
<i v-if="localQuery.length > 0"
class="sn-icon cursor-pointer sn-icon-close absolute right-0 -top-0.5"
@click="localQuery = ''; $refs.searchField.focus()"></i>
</div>
</template>
<template v-slot:flyout >
<div v-for="(query, i) in reversedPreviousQueries" @click="setQuery(query)" :key="i"
ref="historyItems"
tabindex="1"
@keydown.enter="setQuery(query)"
class="flex px-3 h-11 items-center gap-2 hover:bg-sn-super-light-grey cursor-pointer">
<i class="sn-icon sn-icon-history-search"></i>
{{ query }}
</div>
</template>
</GeneralDropdown>
<div class="flex items-center gap-2.5">
<button class="btn btn-secondary btn-sm" :class="{'active': activeGroup == 'ExperimentsComponent'}" @click="setActiveGroup('ExperimentsComponent')">
{{ i18n.t('search.index.experiments') }}
@ -42,6 +66,10 @@
<span class="tw-hidden lg:inline">{{ i18n.t('search.index.clear_filters') }}</span>
</button>
</template>
<button v-if="activeGroup" class="btn btn-light btn-sm" @click="resetGroup">
<i class="sn-icon sn-icon-undo"></i>
<span class="tw-hidden lg:inline">{{ i18n.t('search.index.all_results') }}</span>
</button>
</div>
<template v-for="group in searchGroups">
<component
@ -57,7 +85,7 @@
@updated="calculateTotalElements"
/>
</template>
<div v-if="totalElements === 0 && !loading" class="bg-white rounded p-4">
<div v-if="totalElements === 0" class="bg-white rounded p-4">
<NoSearchResult />
</div>
<teleport to='body'>
@ -136,6 +164,8 @@ export default {
filters: {},
localQuery: this.query,
filterModalOpened: false,
previousQueries: [],
invalidQuery: false,
activeGroup: null,
totalElements: 0,
searchGroups: [
@ -154,9 +184,6 @@ export default {
};
},
computed: {
invalidQuery() {
return this.localQuery.length < 2;
},
activeFilters() {
return Object.keys(this.filters).filter((key) => {
if (key === 'created_at' || key === 'updated_at') {
@ -166,6 +193,12 @@ export default {
}
return this.filters[key];
});
},
canOpenHistory() {
return this.previousQueries.length > 0 && this.localQuery.length === 0;
},
reversedPreviousQueries() {
return [...this.previousQueries].reverse();
}
},
created() {
@ -197,6 +230,8 @@ export default {
if (this.filters.group) {
this.activeGroup = this.filters.group;
}
this.previousQueries = JSON.parse(localStorage.getItem('quickSearchHistory') || '[]');
},
methods: {
calculateTotalElements() {
@ -217,8 +252,38 @@ export default {
this.filters.group = this.activeGroup;
},
setQuery(query) {
this.localQuery = query;
this.invalidQuery = false;
this.$refs.historyContainer.isOpen = false;
},
changeQuery(event) {
if (event.target.value === this.localQuery) {
return;
}
this.localQuery = event.target.value;
if (event.target.value.length < 2) {
this.invalidQuery = true;
return;
}
this.invalidQuery = false;
this.saveQuery();
},
saveQuery() {
if (this.localQuery.length > 1) {
if (this.previousQueries[this.previousQueries.length - 1] === this.localQuery) return;
this.previousQueries.push(this.localQuery);
if (this.previousQueries.length > 5) {
this.previousQueries.shift();
}
localStorage.setItem('quickSearchHistory', JSON.stringify(this.previousQueries));
this.$refs.historyContainer.isOpen = false;
}
},
applyFilters(filters) {
this.filters = filters;
@ -226,6 +291,10 @@ export default {
this.activeGroup = this.filters.group;
},
resetGroup() {
this.activeGroup = null;
this.filters.group = null;
},
resetFilters() {
this.filters = {
created_at: {

View file

@ -1,7 +1,13 @@
<template>
<a target="_blank" :href="url" class="h-full py-2 px-4 overflow-hidden font-bold flex gap-1 items-center group-hover:bg-sn-super-light-grey hover:no-underline">
<a target="_blank" :href="url"
class="h-full py-2 px-4 flex gap-1 items-center font-bold overflow-hidden group-hover:bg-sn-super-light-grey hover:no-underline"
>
<span v-if="icon" :class="icon" class="sn-icon shrink-0"></span>
<StringWithEllipsis class="w-full"
<StringWithEllipsis
:class="{
'w-full': !icon,
'w-[calc(100%-2rem)]': icon
}"
:text="value">
</StringWithEllipsis>
</a>

View file

@ -7,7 +7,7 @@
@focus="openHistory" :placeholder="i18n.t('nav.search')" @keyup.enter="saveQuery"/>
<i class="sn-icon sn-icon-search"></i>
<div v-if="this.searchQuery.length > 1" class="flex items-center gap-1 absolute right-2 top-1.5">
<div class="btn btn-light icon-btn btn-xs" @click="this.searchQuery = ''">
<div class="btn btn-light icon-btn btn-xs" @click="this.searchQuery = ''; $refs.searchField.focus()">
<i class="sn-icon sn-icon-close m-0"></i>
</div>
<div class="btn btn-light icon-btn btn-xs" :title="i18n.t('search.quick_search.search_options')"
@ -96,7 +96,7 @@
<div v-if="!loading && results.length === 0" class="p-2 flex items-center gap-6">
<i class="sn-icon sn-icon-search text-sn-sleepy-grey" style="font-size: 64px !important;"></i>
<div>
<b>{{ i18n.t('search.quick_search.empty_title') }}</b>
<b>{{ i18n.t('search.quick_search.empty_title', {team: currentTeamName}) }}</b>
<div class="text-xs text-sn-dark-grey">
{{ i18n.t('search.quick_search.empty_description', {query: searchQuery}) }}
</div>
@ -147,13 +147,16 @@ export default {
},
computed: {
reversedPreviousQueries() {
return this.previousQueries.reverse();
return [...this.previousQueries].reverse();
},
canOpen() {
return this.previousQueries.length > 0 || this.searchQuery.length > 1;
},
showHistory() {
return this.searchQuery.length < 2;
},
currentTeamName() {
return document.querySelector('body').dataset.currentTeamName;
}
},
watch: {
@ -262,11 +265,11 @@ export default {
});
},
saveQuery() {
if (this.searchQuery.length > 0) {
if (this.searchQuery.length > 1) {
this.previousQueries.push(this.searchQuery);
if (this.previousQueries.length > 5) {
this.previousQueries.shift();
this.previousQueries = this.previousQueries.slice(1);
}
localStorage.setItem('quickSearchHistory', JSON.stringify(this.previousQueries));

View file

@ -67,6 +67,7 @@
class="<%= yield :body_class %> <%= 'navigator-collapsed' if !@navigator || session[:navigator_collapsed] %> <%= 'w-[98%]' if params[:controller] == 'label_templates' && params[:action] == 'show'%>"
<% if user_signed_in? && current_team.present? %>
data-current-team-id="<%= current_team.id %>"
data-current-team-name="<%= current_team.name %>"
data-atwho-users-url="<%= atwho_users_team_path(current_team) %>"
data-atwho-task-url="<%= atwho_my_modules_team_path(current_team) %>"
data-atwho-project-url="<%= atwho_projects_team_path(current_team) %>"

View file

@ -448,7 +448,7 @@ en:
results: "Results"
inventory_items: "Inventory items"
all_results: "All search results for \"%{query}\""
empty_title: "No quick search results found."
empty_title: "No quick search results found in %{team}."
empty_description: "Quick search only checks titles. Press enter or click \"All search results for '%{query}'\" to find all available matches."
search_options: "Search options"
project: "Project"
@ -508,6 +508,7 @@ en:
repository: "Inventory"
more_search_options: "More search options"
clear_filters: "Clear filters"
all_results: "All results"
id: "ID"
created_at: "Created on"
created_by: "Created by"

Binary file not shown.

View file

@ -194,4 +194,5 @@
<glyph unicode="&#xe9a5;" glyph-name="experiment-mini" data-tags="experiment-mini" d="M307.929 140.8c-22.141 0-37.673 9.815-46.598 29.44-8.958 19.625-6.625 37.545 7 53.76l141.471 257.28v222.72h-70.255c-7.664 0-13.847 2.56-18.547 7.68-4.667 5.12-7 11.094-7 17.92 0 7.68 2.333 13.875 7 18.586 4.701 4.676 10.883 7.014 18.547 7.014h344.89c7.665 0 13.844-2.56 18.545-7.68 4.669-5.12 6.999-11.094 6.999-17.92 0-7.68-2.33-13.858-6.999-18.534-4.7-4.71-10.88-7.066-18.545-7.066h-70.257v-222.72l141.471-257.28c13.624-16.215 15.974-34.135 7.050-53.76-8.955-19.625-24.509-29.44-46.648-29.44h-408.124zM307.929 192h408.124l-152.965 271.36v240.64h-102.191v-240.64l-152.968-271.36z" />
<glyph unicode="&#xe9a6;" glyph-name="task-mini" data-tags="task-mini" d="M339.2 140.8c-23.894 0-43.725 7.885-59.494 23.654-15.804 15.805-23.706 35.651-23.706 59.546v448c0 23.894 7.902 43.742 23.706 59.546 15.77 15.77 35.601 23.654 59.494 23.654h249.6l179.2-179.2v-352c0-23.895-7.885-43.74-23.654-59.546-15.805-15.77-35.651-23.654-59.546-23.654h-345.6zM563.2 550.4v153.6h-224c-8.534 0-15.991-3.209-22.374-9.626-6.417-6.383-9.626-13.841-9.626-22.374v-448c0-8.535 3.209-15.99 9.626-22.374 6.383-6.415 13.841-9.626 22.374-9.626h345.6c8.535 0 15.99 3.21 22.374 9.626 6.415 6.385 9.626 13.839 9.626 22.374v326.4h-153.6zM652.984 468.48l-171.313-228.413-123.272 123.269 36.204 36.209 81.528-81.531 135.892 181.187 40.96-30.72z" />
<glyph unicode="&#xe9a7;" glyph-name="flag" data-tags="flag" d="M256 128v661.333h306.871l17.067-85.333h230.729v-341.333h-221.538l-17.067 85.333h-273.395v-320h-42.667zM625.067 405.333h142.933v256h-224l-17.067 85.333h-228.267v-256h309.333l17.067-85.333z" />
<glyph unicode="&#xe9a8;" glyph-name="undo" data-tags="undo" d="M315.893 192v42.667h309.506c44.25 0 81.954 15.181 113.109 45.538 31.142 30.357 46.72 67.413 46.72 111.177s-15.578 80.687-46.72 110.775c-31.155 30.084-68.86 45.129-113.109 45.129h-330.338l126.517-126.528-30.197-30.199-178.048 178.061 178.048 178.048 30.197-30.197-126.517-126.517h330.338c55.851 0 103.561-19.257 143.134-57.771 39.573-38.507 59.362-85.44 59.362-140.8 0-55.351-19.789-102.421-59.362-141.205s-87.283-58.176-143.134-58.176h-309.506z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Binary file not shown.

View file

@ -1,11 +1,11 @@
@font-face {
font-family: 'SN-icon-font';
src: url('fonts/SN-icon-font.eot?o0xor4');
src: url('fonts/SN-icon-font.eot?o0xor4#iefix') format('embedded-opentype'),
url('fonts/SN-icon-font.woff2?o0xor4') format('woff2'),
url('fonts/SN-icon-font.ttf?o0xor4') format('truetype'),
url('fonts/SN-icon-font.woff?o0xor4') format('woff'),
url('fonts/SN-icon-font.svg?o0xor4#SN-icon-font') format('svg');
src: url('fonts/SN-icon-font.eot?m1g5fz');
src: url('fonts/SN-icon-font.eot?m1g5fz#iefix') format('embedded-opentype'),
url('fonts/SN-icon-font.woff2?m1g5fz') format('woff2'),
url('fonts/SN-icon-font.ttf?m1g5fz') format('truetype'),
url('fonts/SN-icon-font.woff?m1g5fz') format('woff'),
url('fonts/SN-icon-font.svg?m1g5fz#SN-icon-font') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
@ -530,3 +530,6 @@
.sn-icon-flag:before {
content: "\e9a7";
}
.sn-icon-undo:before {
content: "\e9a8";
}