mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-07 14:05:44 +01:00
Filer repositories in UI by namespace
This commit is contained in:
@@ -132,9 +132,9 @@ class LinkPaginator extends React.Component<Props> {
|
|||||||
<nav className="pagination is-centered" aria-label="pagination">
|
<nav className="pagination is-centered" aria-label="pagination">
|
||||||
{this.renderPreviousButton("pagination-previous", t("paginator.previous"))}
|
{this.renderPreviousButton("pagination-previous", t("paginator.previous"))}
|
||||||
<ul className="pagination-list">
|
<ul className="pagination-list">
|
||||||
{this.pageLinks().map((link, index) => {
|
{this.pageLinks().map((link, index) => (
|
||||||
return <li key={index}>{link}</li>;
|
<li key={index}>{link}</li>
|
||||||
})}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
{this.renderNextButton("pagination-next", t("paginator.next"))}
|
{this.renderNextButton("pagination-next", t("paginator.next"))}
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -22,7 +22,12 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { concat, getPageFromMatch, getQueryStringFromLocation, withEndingSlash } from "./urls";
|
import {
|
||||||
|
concat,
|
||||||
|
getNamespaceAndPageFromMatch,
|
||||||
|
getQueryStringFromLocation,
|
||||||
|
withEndingSlash
|
||||||
|
} from "./urls";
|
||||||
|
|
||||||
describe("tests for withEndingSlash", () => {
|
describe("tests for withEndingSlash", () => {
|
||||||
it("should append missing slash", () => {
|
it("should append missing slash", () => {
|
||||||
@@ -42,28 +47,41 @@ describe("concat tests", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("tests for getPageFromMatch", () => {
|
describe("tests for getNamespaceAndPageFromMatch", () => {
|
||||||
function createMatch(page: string) {
|
function createMatch(namespace?: string, page?: string) {
|
||||||
return {
|
return {
|
||||||
params: {
|
params: { namespace, page }
|
||||||
page
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
it("should return 1 for NaN", () => {
|
it("should return no namespace and page 1 for neither namespace nor page", () => {
|
||||||
const match = createMatch("any");
|
const match = createMatch();
|
||||||
expect(getPageFromMatch(match)).toBe(1);
|
expect(getNamespaceAndPageFromMatch(match)).toEqual({ namespace: undefined, page: 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return 1 for 0", () => {
|
it("should return no namespace and page 1 for 0 as only parameter", () => {
|
||||||
const match = createMatch("0");
|
const match = createMatch("0");
|
||||||
expect(getPageFromMatch(match)).toBe(1);
|
expect(getNamespaceAndPageFromMatch(match)).toEqual({ namespace: undefined, page: 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return the given number", () => {
|
it("should return no namespace and given number as page, when only a number is given", () => {
|
||||||
const match = createMatch("42");
|
const match = createMatch("42");
|
||||||
expect(getPageFromMatch(match)).toBe(42);
|
expect(getNamespaceAndPageFromMatch(match)).toEqual({ namespace: undefined, page: 42 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return big number as namespace and page 1, when only a big number is given", () => {
|
||||||
|
const match = createMatch("1337");
|
||||||
|
expect(getNamespaceAndPageFromMatch(match)).toEqual({ namespace: "1337", page: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should namespace and page 1, when only a string is given", () => {
|
||||||
|
const match = createMatch("something");
|
||||||
|
expect(getNamespaceAndPageFromMatch(match)).toEqual({ namespace: "something", page: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should namespace and given page, when namespace and page are given", () => {
|
||||||
|
const match = createMatch("something", "42");
|
||||||
|
expect(getNamespaceAndPageFromMatch(match)).toEqual({ namespace: "something", page: 42 });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -46,10 +46,33 @@ export function concat(base: string, ...parts: string[]) {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNamespaceAndPageFromMatch(match: any) {
|
||||||
|
const namespaceFromMatch: string = match.params.namespace;
|
||||||
|
const pageFromMatch: string = match.params.page;
|
||||||
|
|
||||||
|
if (!namespaceFromMatch && !pageFromMatch) {
|
||||||
|
return { namespace: undefined, page: 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pageFromMatch) {
|
||||||
|
if (namespaceFromMatch.match(/^\d{1,3}$/)) {
|
||||||
|
return { namespace: undefined, page: parsePageNumber(namespaceFromMatch) };
|
||||||
|
} else {
|
||||||
|
return { namespace: namespaceFromMatch, page: 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { namespace: namespaceFromMatch, page: parsePageNumber(pageFromMatch) };
|
||||||
|
}
|
||||||
|
|
||||||
export function getPageFromMatch(match: any) {
|
export function getPageFromMatch(match: any) {
|
||||||
let page = parseInt(match.params.page, 10);
|
return parsePageNumber(match.params.page);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parsePageNumber(pageAsString: string) {
|
||||||
|
const page = parseInt(pageAsString, 10);
|
||||||
if (isNaN(page) || !page) {
|
if (isNaN(page) || !page) {
|
||||||
page = 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ class Main extends React.Component<Props> {
|
|||||||
<Redirect exact strict from="/repos" to="/repos/" />
|
<Redirect exact strict from="/repos" to="/repos/" />
|
||||||
<ProtectedRoute exact path="/repos/" component={Overview} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/" component={Overview} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/repos/create" component={Create} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/create" component={Create} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/repos/:page" component={Overview} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/:namespace" component={Overview} authenticated={authenticated} />
|
||||||
|
<ProtectedRoute exact path="/repos/:namespace/:page" component={Overview} authenticated={authenticated} />
|
||||||
<ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} />
|
<ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} />
|
||||||
<Redirect exact strict from="/users" to="/users/" />
|
<Redirect exact strict from="/users" to="/users/" />
|
||||||
<ProtectedRoute exact path="/users/" component={Users} authenticated={authenticated} />
|
<ProtectedRoute exact path="/users/" component={Users} authenticated={authenticated} />
|
||||||
|
|||||||
@@ -52,30 +52,33 @@ type Props = WithTranslation &
|
|||||||
showCreateButton: boolean;
|
showCreateButton: boolean;
|
||||||
collection: RepositoryCollection;
|
collection: RepositoryCollection;
|
||||||
page: number;
|
page: number;
|
||||||
|
namespace: string;
|
||||||
reposLink: string;
|
reposLink: string;
|
||||||
|
|
||||||
// dispatched functions
|
// dispatched functions
|
||||||
fetchReposByPage: (link: string, page: number, filter?: string) => void;
|
fetchReposByPage: (link: string, page: number, namespace?: string, filter?: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Overview extends React.Component<Props> {
|
class Overview extends React.Component<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { fetchReposByPage, reposLink, page, location } = this.props;
|
const { fetchReposByPage, reposLink, namespace, page, location } = this.props;
|
||||||
fetchReposByPage(reposLink, page, urls.getQueryStringFromLocation(location));
|
fetchReposByPage(reposLink, page, namespace, urls.getQueryStringFromLocation(location));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate = (prevProps: Props) => {
|
componentDidUpdate = (prevProps: Props) => {
|
||||||
const { loading, collection, page, reposLink, location, fetchReposByPage } = this.props;
|
const { loading, collection, namespace, page, reposLink, location, fetchReposByPage } = this.props;
|
||||||
if (collection && page && !loading) {
|
if (collection && page && !loading) {
|
||||||
const statePage: number = collection.page + 1;
|
const statePage: number = collection.page + 1;
|
||||||
if (page !== statePage || prevProps.location.search !== location.search) {
|
if (page !== statePage || prevProps.location.search !== location.search) {
|
||||||
fetchReposByPage(reposLink, page, urls.getQueryStringFromLocation(location));
|
fetchReposByPage(reposLink, page, namespace, urls.getQueryStringFromLocation(location));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { error, loading, showCreateButton, t } = this.props;
|
const { error, loading, showCreateButton, namespace, t } = this.props;
|
||||||
|
|
||||||
|
const link = namespace ? `repos/${namespace}` : "repos";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title={t("overview.title")} subtitle={t("overview.subtitle")} loading={loading} error={error}>
|
<Page title={t("overview.title")} subtitle={t("overview.subtitle")} loading={loading} error={error}>
|
||||||
@@ -83,7 +86,7 @@ class Overview extends React.Component<Props> {
|
|||||||
<PageActions>
|
<PageActions>
|
||||||
<OverviewPageActions
|
<OverviewPageActions
|
||||||
showCreateButton={showCreateButton}
|
showCreateButton={showCreateButton}
|
||||||
link="repos"
|
link={link}
|
||||||
label={t("overview.createButton")}
|
label={t("overview.createButton")}
|
||||||
testId="repository-overview"
|
testId="repository-overview"
|
||||||
/>
|
/>
|
||||||
@@ -133,7 +136,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
const collection = getRepositoryCollection(state);
|
const collection = getRepositoryCollection(state);
|
||||||
const loading = isFetchReposPending(state);
|
const loading = isFetchReposPending(state);
|
||||||
const error = getFetchReposFailure(state);
|
const error = getFetchReposFailure(state);
|
||||||
const page = urls.getPageFromMatch(match);
|
const { namespace, page } = urls.getNamespaceAndPageFromMatch(match);
|
||||||
const showCreateButton = isAbleToCreateRepos(state);
|
const showCreateButton = isAbleToCreateRepos(state);
|
||||||
const reposLink = getRepositoriesLink(state);
|
const reposLink = getRepositoriesLink(state);
|
||||||
return {
|
return {
|
||||||
@@ -141,6 +144,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
page,
|
page,
|
||||||
|
namespace,
|
||||||
showCreateButton,
|
showCreateButton,
|
||||||
reposLink
|
reposLink
|
||||||
};
|
};
|
||||||
@@ -148,9 +152,10 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => {
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
return {
|
return {
|
||||||
fetchReposByPage: (link: string, page: number, filter?: string) => {
|
fetchReposByPage: (link: string, page: number, namespace?: string, filter?: string) => {
|
||||||
dispatch(fetchReposByPage(link, page, filter));
|
dispatch(fetchReposByPage(link, page, namespace, filter));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(withRouter(Overview)));
|
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(withRouter(Overview)));
|
||||||
|
|||||||
@@ -67,11 +67,13 @@ export function fetchRepos(link: string) {
|
|||||||
return fetchReposByLink(link);
|
return fetchReposByLink(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchReposByPage(link: string, page: number, filter?: string) {
|
export function fetchReposByPage(link: string, page: number, namespace?: string, filter?: string) {
|
||||||
|
const namespacePath = namespace ? `${namespace}/` : "";
|
||||||
|
const linkWithPage = `${link}${namespacePath}?page=${page - 1}`;
|
||||||
if (filter) {
|
if (filter) {
|
||||||
return fetchReposByLink(`${link}?page=${page - 1}&q=${decodeURIComponent(filter)}`);
|
return fetchReposByLink(`${linkWithPage}}&q=${decodeURIComponent(filter)}`);
|
||||||
}
|
}
|
||||||
return fetchReposByLink(`${link}?page=${page - 1}`);
|
return fetchReposByLink(linkWithPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendSortByLink(url: string) {
|
function appendSortByLink(url: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user