From 3e236fe5acb0541145bc36fc33ba9e18bce34117 Mon Sep 17 00:00:00 2001 From: Matthias Thieroff Date: Thu, 18 Aug 2022 09:04:45 +0200 Subject: [PATCH] Optimize global search result view (#2107) Enhance search result view by sorting the categories after their translation (repositories will still be sticky on top). Further disable categories with no search results and be more explicit with the text displayed if no search results were found. --- gradle/changelog/optimize_global_search.yaml | 2 + .../ui-webapp/public/locales/de/commons.json | 2 +- .../ui-webapp/public/locales/en/commons.json | 2 +- .../ui-webapp/src/containers/OmniSearch.tsx | 11 ++- scm-ui/ui-webapp/src/search/Results.tsx | 10 +-- scm-ui/ui-webapp/src/search/Search.tsx | 83 ++++++++++++------- 6 files changed, 69 insertions(+), 41 deletions(-) create mode 100644 gradle/changelog/optimize_global_search.yaml diff --git a/gradle/changelog/optimize_global_search.yaml b/gradle/changelog/optimize_global_search.yaml new file mode 100644 index 0000000000..48ddffef68 --- /dev/null +++ b/gradle/changelog/optimize_global_search.yaml @@ -0,0 +1,2 @@ +- type: changed + description: Enhance search result view by sorting translated categories and disable categories with no search results ([#2107](https://github.com/scm-manager/scm-manager/pull/2107)) diff --git a/scm-ui/ui-webapp/public/locales/de/commons.json b/scm-ui/ui-webapp/public/locales/de/commons.json index 75766e368c..a63ecb0981 100644 --- a/scm-ui/ui-webapp/public/locales/de/commons.json +++ b/scm-ui/ui-webapp/public/locales/de/commons.json @@ -203,7 +203,7 @@ "subtitle": "{{type}} Ergebnisse für \"{{query}}\"", "subtitleWithContext": "{{type}} Ergebnisse für \"{{query}}\" in \"{{context}}\"", "types": "Ergebnisse", - "noHits": "Die Suche ergab keine Treffer", + "noHits": "Keine Ergebnisse gefunden. Auf der rechten Seite finden Sie weitere Kategorien, in denen Ergebnisse vorhanden sein könnten", "syntaxHelp": "Finden Sie bessere Ergebnisse durch die Nutzung der vollen <0>Such-Syntax", "quickSearch": { "resultHeading": "Hilfe beim Suchen?", diff --git a/scm-ui/ui-webapp/public/locales/en/commons.json b/scm-ui/ui-webapp/public/locales/en/commons.json index c9cffe71ee..2c572cc18b 100644 --- a/scm-ui/ui-webapp/public/locales/en/commons.json +++ b/scm-ui/ui-webapp/public/locales/en/commons.json @@ -204,7 +204,7 @@ "subtitle": "{{type}} results for \"{{query}}\"", "subtitleWithContext": "{{type}} results for \"{{query}}\" in \"{{context}}\"", "types": "Results", - "noHits": "No results found", + "noHits": "No results found. On the right side you will find other categories where results might be available", "syntaxHelp": "Find better results by using the full <0>search syntax", "quickSearch": { "resultHeading": "Need help?", diff --git a/scm-ui/ui-webapp/src/containers/OmniSearch.tsx b/scm-ui/ui-webapp/src/containers/OmniSearch.tsx index 85bb3aad8e..a3e505ed63 100644 --- a/scm-ui/ui-webapp/src/containers/OmniSearch.tsx +++ b/scm-ui/ui-webapp/src/containers/OmniSearch.tsx @@ -95,7 +95,7 @@ const AvatarSection: FC<{ repository: Repository }> = ({ repository }) => { ); }; -const HitsList: FC> = ({ entries }) => { +const HitList: FC> = ({ entries }) => { return (
    {entries} @@ -155,7 +155,7 @@ const Hits: FC = ({ entries, hits, showHelp, ...rest }) => { <>
    - + { namespaceContext: context.namespace || "", repositoryNameContext: context.name || "", }); - searchTypes.sort(orderTypes); + searchTypes.sort(orderTypes(t)); const id = useCallback(namespaceAndName, []); @@ -362,6 +362,7 @@ const OmniSearch: FC = () => { if (context.namespace && context.name && searchTypes.length > 0) { newEntries.push( { if (context.namespace) { newEntries.push( { } newEntries.push( { hits?.forEach((hit, idx) => { newEntries.push( = ({ result, type, page, query }) => { } return ( -
    - -
    - + <> +
    +
    -
    + + ); }; diff --git a/scm-ui/ui-webapp/src/search/Search.tsx b/scm-ui/ui-webapp/src/search/Search.tsx index 97a9d901fa..c258038c5d 100644 --- a/scm-ui/ui-webapp/src/search/Search.tsx +++ b/scm-ui/ui-webapp/src/search/Search.tsx @@ -34,11 +34,18 @@ import { urls, } from "@scm-manager/ui-components"; import { Link, useLocation, useParams } from "react-router-dom"; -import { useSearch, useSearchCounts, useSearchTypes, useNamespaceAndNameContext } from "@scm-manager/ui-api"; +import { useNamespaceAndNameContext, useSearch, useSearchCounts, useSearchTypes } from "@scm-manager/ui-api"; import Results from "./Results"; import { Trans, useTranslation } from "react-i18next"; import SearchErrorNotification from "./SearchErrorNotification"; import SyntaxModal from "./SyntaxModal"; +import type { TFunction } from "i18next"; +import styled from "styled-components"; + +const DisabledNavLink = styled.div` + opacity: 0.4; + cursor: not-allowed; +`; type PathParams = { type: string; @@ -80,17 +87,16 @@ const usePageParams = () => { }; }; -export const orderTypes = (left: string, right: string) => { - if (left === "repository" && right !== "repository") { +export const orderTypes = (t: TFunction) => (a: string, b: string) => { + if (!a || !b) { + return 0; + } + if (a === "repository" && b !== "repository") { return -1; - } else if (left !== "repository" && right === "repository") { - return 1; - } else if (left < right) { - return -1; - } else if (left > right) { + } else if (a !== "repository" && b === "repository") { return 1; } - return 0; + return t(`plugins:search.types.${a}.navItem`, a)?.localeCompare(t(`plugins:search.types.${b}.navItem`, b)) ?? 0; }; type Props = { @@ -144,7 +150,7 @@ const Search: FC = () => { }; const { data, isLoading, error } = useSearch(query, searchOptions); const types = useSearchTypes(searchOptions); - types.sort(orderTypes); + types.sort(orderTypes(t)); const searchCounts = useSearchCounts( types.filter((type) => type !== selectedType), @@ -174,27 +180,44 @@ const Search: FC = () => { - {types.map((type) => ( - - + type !== selectedType && (counts[type].isLoading || counts[type].data === 0) ? ( +
  • + + + } /> - } - /> - - ))} + +
  • + ) : ( + + + } + /> + + ) + )}
    ) : null}