mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-07 22:15:45 +01:00
Fix repository file search (#1867)
This commit is contained in:
committed by
René Pfeuffer
parent
02bcee5603
commit
e58d3dd70c
2
gradle/changelog/fix_file_search.yaml
Normal file
2
gradle/changelog/fix_file_search.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
- type: fixed
|
||||||
|
description: Repository file search ([#1867](https://github.com/scm-manager/scm-manager/pull/1867))
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#
|
||||||
|
# MIT License
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
Feature: Repository File Search
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given User is authenticated
|
||||||
|
And A git repository exists
|
||||||
|
|
||||||
|
Scenario: Search file inside repository
|
||||||
|
Given User has permission to read and write repository
|
||||||
|
When User visits repository
|
||||||
|
And User performs file search inside repository
|
||||||
|
Then The search results are found
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
When("User visits repository", function() {
|
||||||
|
cy.visit(`/repo/${this.repository.namespace}/${this.repository.name}/code/sources`);
|
||||||
|
});
|
||||||
|
|
||||||
|
When("User performs file search inside repository", function() {
|
||||||
|
cy.byTestId("file_search_button").click();
|
||||||
|
cy.url().should("include", `/repo/${this.repository.namespace}/${this.repository.name}/code/search/main?q=`);
|
||||||
|
cy.get("[data-testid=file_search_filter_input]").type("README");
|
||||||
|
});
|
||||||
|
|
||||||
|
Then("The search results are found", function() {
|
||||||
|
cy.get("[data-testid=file_search_single_result]").contains("README.md");
|
||||||
|
});
|
||||||
@@ -67,20 +67,17 @@ const FilterInput: FC<Props> = ({ filter, value, testId, placeholder, autoFocus,
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form className={classNames("input-field", className)} onSubmit={handleSubmit}>
|
||||||
className={classNames("input-field", className)}
|
|
||||||
onSubmit={handleSubmit}
|
|
||||||
{...createAttributesForTesting(testId)}
|
|
||||||
>
|
|
||||||
<div className="control has-icons-left">
|
<div className="control has-icons-left">
|
||||||
<FixedHeightInput
|
<FixedHeightInput
|
||||||
className="input"
|
className="input"
|
||||||
type="search"
|
type="search"
|
||||||
placeholder={placeholder || t("filterEntries")}
|
placeholder={placeholder || t("filterEntries")}
|
||||||
value={stateValue}
|
value={stateValue}
|
||||||
onChange={(event) => setStateValue(event.target.value)}
|
onChange={event => setStateValue(event.target.value)}
|
||||||
autoFocus={autoFocus || false}
|
autoFocus={autoFocus || false}
|
||||||
aria-describedby={id}
|
aria-describedby={id}
|
||||||
|
{...createAttributesForTesting(testId)}
|
||||||
/>
|
/>
|
||||||
<span className="icon is-small is-left">
|
<span className="icon is-small is-left">
|
||||||
<i className="fas fa-filter" />
|
<i className="fas fa-filter" />
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ const SearchIcon = styled(Icon)`
|
|||||||
const FileSearchButton: FC<Props> = ({ baseUrl, revision }) => {
|
const FileSearchButton: FC<Props> = ({ baseUrl, revision }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
return (
|
return (
|
||||||
<Link to={`${baseUrl}/search/${encodeURIComponent(revision)}`} aria-label={t("fileSearch.button.title")}>
|
<Link
|
||||||
|
to={`${baseUrl}/search/${encodeURIComponent(revision)}`}
|
||||||
|
aria-label={t("fileSearch.button.title")}
|
||||||
|
data-testid="file_search_button"
|
||||||
|
>
|
||||||
<SearchIcon title={t("fileSearch.button.title")} name="search" color="inherit" />
|
<SearchIcon title={t("fileSearch.button.title")} name="search" color="inherit" />
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const PathResultRow: FC<PathResultRowProps> = ({ contentBaseUrl, path }) => {
|
|||||||
</Link>
|
</Link>
|
||||||
</IconColumn>
|
</IconColumn>
|
||||||
<LeftOverflowTd>
|
<LeftOverflowTd>
|
||||||
<Link title={path} to={link}>
|
<Link title={path} to={link} data-testid="file_search_single_result">
|
||||||
{path}
|
{path}
|
||||||
</Link>
|
</Link>
|
||||||
</LeftOverflowTd>
|
</LeftOverflowTd>
|
||||||
@@ -78,7 +78,7 @@ type ResultTableProps = {
|
|||||||
const ResultTable: FC<ResultTableProps> = ({ contentBaseUrl, paths }) => (
|
const ResultTable: FC<ResultTableProps> = ({ contentBaseUrl, paths }) => (
|
||||||
<table className="table table-hover table-sm is-fullwidth">
|
<table className="table table-hover table-sm is-fullwidth">
|
||||||
<tbody>
|
<tbody>
|
||||||
{paths.map((path) => (
|
{paths.map(path => (
|
||||||
<PathResultRow contentBaseUrl={contentBaseUrl} path={path} />
|
<PathResultRow contentBaseUrl={contentBaseUrl} path={path} />
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import classNames from "classnames";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||||
import { urls, usePaths } from "@scm-manager/ui-api";
|
import { urls, usePaths } from "@scm-manager/ui-api";
|
||||||
import { ErrorNotification, FilterInput, Help, Icon, Loading } from "@scm-manager/ui-components";
|
import { createA11yId, ErrorNotification, FilterInput, Help, Icon, Loading } from "@scm-manager/ui-components";
|
||||||
import CodeActionBar from "../components/CodeActionBar";
|
import CodeActionBar from "../components/CodeActionBar";
|
||||||
import FileSearchResults from "../components/FileSearchResults";
|
import FileSearchResults from "../components/FileSearchResults";
|
||||||
import { filepathSearch } from "../utils/filepathSearch";
|
import { filepathSearch } from "../utils/filepathSearch";
|
||||||
@@ -91,7 +91,7 @@ const FileSearch: FC<Props> = ({ repository, baseUrl, branches, selectedBranch }
|
|||||||
};
|
};
|
||||||
|
|
||||||
const contentBaseUrl = `${baseUrl}/sources/${revision}/`;
|
const contentBaseUrl = `${baseUrl}/sources/${revision}/`;
|
||||||
const id = useA11yId("file-search");
|
const id = createA11yId("file-search");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -123,6 +123,7 @@ const FileSearch: FC<Props> = ({ repository, baseUrl, branches, selectedBranch }
|
|||||||
filter={search}
|
filter={search}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
id={id}
|
id={id}
|
||||||
|
testId="file_search_filter_input"
|
||||||
/>
|
/>
|
||||||
<Help className="ml-3" message={t("fileSearch.input.help")} id={id} />
|
<Help className="ml-3" message={t("fileSearch.input.help")} id={id} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user