From: Jeremy Davis Date: Tue, 24 Nov 2020 17:03:05 +0000 (+0100) Subject: SONAR-14057 Highlight search query in results X-Git-Tag: 8.6.0.39681~64 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=836733b9c96cb1e031c6349bf961cde586509784;p=sonarqube.git SONAR-14057 Highlight search query in results --- diff --git a/server/sonar-web/src/main/js/app/styles/init/type.css b/server/sonar-web/src/main/js/app/styles/init/type.css index b04036497ff..f0da00a85dd 100644 --- a/server/sonar-web/src/main/js/app/styles/init/type.css +++ b/server/sonar-web/src/main/js/app/styles/init/type.css @@ -140,6 +140,10 @@ strong { font-weight: 600; } +.underline { + text-decoration: underline; +} + mark { background: none; color: var(--baseFontColor); diff --git a/server/sonar-web/src/main/js/apps/create/project/AzureProjectAccordion.tsx b/server/sonar-web/src/main/js/apps/create/project/AzureProjectAccordion.tsx index b74344df137..ddac1e38947 100644 --- a/server/sonar-web/src/main/js/apps/create/project/AzureProjectAccordion.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/AzureProjectAccordion.tsx @@ -40,14 +40,40 @@ export interface AzureProjectAccordionProps { onSelectRepository: (repository: AzureRepository) => void; project: AzureProject; repositories?: AzureRepository[]; + searchQuery?: string; selectedRepository?: AzureRepository; startsOpen: boolean; } const PAGE_SIZE = 30; +function highlight(text: string, term?: string, underline = false) { + if (!term || !text.toLowerCase().includes(term.toLowerCase())) { + return text; + } + + // Capture only the first occurence by using a capturing group to get + // everything after the first occurence + const [pre, found, post] = text.split(new RegExp(`(${term})(.*)`, 'i')); + return ( + <> + {pre} + {found} + {post} + + ); +} + export default function AzureProjectAccordion(props: AzureProjectAccordionProps) { - const { importing, loading, startsOpen, project, repositories = [], selectedRepository } = props; + const { + importing, + loading, + startsOpen, + project, + repositories = [], + searchQuery, + selectedRepository + } = props; const [open, setOpen] = React.useState(startsOpen); const handleClick = () => { @@ -70,7 +96,7 @@ export default function AzureProjectAccordion(props: AzureProjectAccordionProps) })} onClick={handleClick} open={open} - title={

{project.name}

}> + title={

{highlight(project.name, searchQuery, true)}

}> {open && ( {/* The extra loading guard is to prevent the flash of the Alert */} @@ -97,18 +123,16 @@ export default function AzureProjectAccordion(props: AzureProjectAccordionProps)
{limitedRepositories.map(repo => (
{repo.sqProjectKey ? ( <>
- - - {repo.sqProjectName} - - + + {highlight(repo.sqProjectName || repo.name, searchQuery)} +
{translate('onboarding.create_project.repository_imported')}
@@ -120,9 +144,9 @@ export default function AzureProjectAccordion(props: AzureProjectAccordionProps) disabled={importing} onCheck={() => props.onSelectRepository(repo)} value={repo.name}> - - {repo.name} - + + {highlight(repo.name, searchQuery)} + )}
diff --git a/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx index 88bc3f494e0..84e232efb07 100644 --- a/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx @@ -48,6 +48,7 @@ interface State { repositories: T.Dict; searching?: boolean; searchResults?: T.Dict; + searchQuery?: string; selectedRepository?: AzureRepository; settings?: AlmSettingsInstance; submittingToken?: boolean; @@ -184,7 +185,7 @@ export default class AzureProjectCreate extends React.PureComponent []); if (this.mounted) { - this.setState({ searching: false, searchResults: groupBy(results, 'projectName') }); + this.setState({ + searching: false, + searchResults: groupBy(results, 'projectName'), + searchQuery + }); } }; @@ -277,6 +282,7 @@ export default class AzureProjectCreate extends React.PureComponent; searching?: boolean; searchResults?: T.Dict; + searchQuery?: string; selectedRepository?: AzureRepository; settings?: AlmSettingsInstance; showPersonalAccessTokenForm?: boolean; @@ -61,6 +62,7 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend repositories, searching, searchResults, + searchQuery, selectedRepository, settings, showPersonalAccessTokenForm, @@ -99,7 +101,7 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend {loading && } - {!loading && !settings && ( + {!loading && !(settings && settings.url) && ( )} @@ -119,7 +121,7 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend
@@ -131,6 +133,7 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend projects={projects} repositories={repositories} searchResults={searchResults} + searchQuery={searchQuery} selectedRepository={selectedRepository} /> diff --git a/server/sonar-web/src/main/js/apps/create/project/AzureProjectsList.tsx b/server/sonar-web/src/main/js/apps/create/project/AzureProjectsList.tsx index b0cc921f4a6..89905bfc5df 100644 --- a/server/sonar-web/src/main/js/apps/create/project/AzureProjectsList.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/AzureProjectsList.tsx @@ -35,6 +35,7 @@ export interface AzureProjectsListProps { projects?: AzureProject[]; repositories: T.Dict; searchResults?: T.Dict; + searchQuery?: string; selectedRepository?: AzureRepository; } @@ -47,6 +48,7 @@ export default function AzureProjectsList(props: AzureProjectsListProps) { projects = [], repositories, searchResults, + searchQuery, selectedRepository } = props; @@ -100,6 +102,7 @@ export default function AzureProjectsList(props: AzureProjectsListProps) { project={p} repositories={searchResults ? searchResults[p.name] : repositories[p.name]} selectedRepository={selectedRepository} + searchQuery={searchQuery} startsOpen={searchResults !== undefined || i === 0} /> ))} diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectAccordion-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectAccordion-test.tsx index 61588b9fbf6..8ac44c5280c 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectAccordion-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectAccordion-test.tsx @@ -40,6 +40,19 @@ it('should render correctly', () => { expect(shallowRender({ importing: true, repositories: [mockAzureRepository()] })).toMatchSnapshot( 'importing' ); + expect( + shallowRender({ + repositories: [ + mockAzureRepository({ name: 'this repo is the best' }), + mockAzureRepository({ + name: 'This is a repo with class', + sqProjectKey: 'sq-key', + sqProjectName: 'SQ Name' + }) + ], + searchQuery: 'repo' + }) + ).toMatchSnapshot('search results'); }); it('should open when clicked', () => { diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx index 73b6e225ad1..6c945df40d3 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx @@ -157,6 +157,7 @@ it('should handle searching for repositories', async () => { await waitAndUpdate(wrapper); expect(wrapper.state().searching).toBe(false); expect(wrapper.state().searchResults).toEqual({ [repositories[0].projectName]: repositories }); + expect(wrapper.state().searchQuery).toBe(query); // Ignore opening a project when search results are displayed (getAzureRepositories as jest.Mock).mockClear(); @@ -169,6 +170,7 @@ it('should handle searching for repositories', async () => { wrapper.instance().handleSearchRepositories(''); expect(searchAzureRepositories).not.toBeCalled(); expect(wrapper.state().searchResults).toBeUndefined(); + expect(wrapper.state().searchQuery).toBeUndefined(); }); it('should select and import a repository', async () => { diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectAccordion-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectAccordion-test.tsx.snap index 99d677cb7c7..75ce5ede02c 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectAccordion-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectAccordion-test.tsx.snap @@ -35,7 +35,7 @@ exports[`should render correctly: importing 1`] = ` className="display-flex-wrap" >
- Azure repo 1 - +
@@ -91,6 +91,97 @@ exports[`should render correctly: loading 1`] = ` `; +exports[`should render correctly: search results 1`] = ` + + azure-project-1 + + } +> + +
+
+ + + this + + repo + + is the best + + +
+
+ +
+
+ + SQ Name + +
+ + onboarding.create_project.repository_imported + +
+
+
+ +
+
+`; + exports[`should render correctly: with repositories 1`] = `
- Azure repo 1 - +
- - - SQ Name - - + } + > + SQ Name +
onboarding.create_project.repository_imported diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap index 68879175e51..ea0a2ef9a3f 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap @@ -115,12 +115,16 @@ exports[`should render correctly: project list 1`] = ` } /> +
} /> +
diff --git a/server/sonar-web/src/main/js/apps/create/project/style.css b/server/sonar-web/src/main/js/apps/create/project/style.css index d2e9420fcbd..832494dfa18 100644 --- a/server/sonar-web/src/main/js/apps/create/project/style.css +++ b/server/sonar-web/src/main/js/apps/create/project/style.css @@ -35,8 +35,10 @@ } .create-project-azdo-repo { - width: 250px; + width: 410px; min-height: 40px; + box-sizing: border-box; + margin-right: auto; } .create-project-import-bbs .open .boxed-group-header { diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index a0717a0f97e..65f0a4d9e6e 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3239,6 +3239,7 @@ onboarding.create_project.display_name.help=Some scanners might override the val onboarding.create_project.repository_imported=Already set up onboarding.create_project.see_project=See the project onboarding.create_project.search_repositories_by_name=Search for repository name starting with... +onboarding.create_project.search_projects_repositories=Search for projects and repositories onboarding.create_project.search_repositories=Search for a repository onboarding.create_project.select_repositories=Select repositories onboarding.create_project.select_all_repositories=Select all available repositories