mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 14:35:45 +01:00
Get links for repositories by namespaces from server
This commit is contained in:
@@ -39,12 +39,19 @@ export type RepositoryCreation = Repository & {
|
||||
contextEntries: { [key: string]: any };
|
||||
};
|
||||
|
||||
export type Namespace = {
|
||||
namespace: string;
|
||||
_links: Links;
|
||||
};
|
||||
|
||||
export type RepositoryCollection = PagedCollection & {
|
||||
_embedded: {
|
||||
repositories: Repository[] | string[];
|
||||
};
|
||||
};
|
||||
|
||||
export type NamespaceCollection = Namespace[];
|
||||
|
||||
export type RepositoryGroup = {
|
||||
name: string;
|
||||
repositories: Repository[];
|
||||
|
||||
@@ -29,7 +29,7 @@ export { Me } from "./Me";
|
||||
export { DisplayedUser, User } from "./User";
|
||||
export { Group, Member } from "./Group";
|
||||
|
||||
export { Repository, RepositoryCollection, RepositoryGroup, RepositoryCreation } from "./Repositories";
|
||||
export { Repository, RepositoryCollection, RepositoryGroup, RepositoryCreation, Namespace, NamespaceCollection } from "./Repositories";
|
||||
export { RepositoryType, RepositoryTypeCollection } from "./RepositoryTypes";
|
||||
|
||||
export { Branch, BranchRequest } from "./Branches";
|
||||
|
||||
@@ -234,6 +234,10 @@ export function getRepositoriesLink(state: object) {
|
||||
return getLink(state, "repositories");
|
||||
}
|
||||
|
||||
export function getNamespacesLink(state: object) {
|
||||
return getLink(state, "namespaces");
|
||||
}
|
||||
|
||||
export function getHgConfigLink(state: object) {
|
||||
return getLink(state, "hgConfig");
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { RouteComponentProps, withRouter } from "react-router-dom";
|
||||
import { WithTranslation, withTranslation } from "react-i18next";
|
||||
import { RepositoryCollection } from "@scm-manager/ui-types";
|
||||
import { NamespaceCollection, RepositoryCollection } from "@scm-manager/ui-types";
|
||||
import {
|
||||
CreateButton,
|
||||
LinkPaginator,
|
||||
@@ -35,13 +35,16 @@ import {
|
||||
PageActions,
|
||||
urls
|
||||
} from "@scm-manager/ui-components";
|
||||
import { getRepositoriesLink } from "../../modules/indexResource";
|
||||
import { getNamespacesLink, getRepositoriesLink } from "../../modules/indexResource";
|
||||
import {
|
||||
fetchReposByPage,
|
||||
getFetchReposFailure,
|
||||
getRepositoryCollection,
|
||||
isAbleToCreateRepos,
|
||||
isFetchReposPending
|
||||
isFetchReposPending,
|
||||
isFetchNamespacesPending,
|
||||
getNamespaceCollection,
|
||||
fetchNamespaces
|
||||
} from "../modules/repos";
|
||||
import RepositoryList from "../components/list";
|
||||
|
||||
@@ -51,30 +54,52 @@ type Props = WithTranslation &
|
||||
error: Error;
|
||||
showCreateButton: boolean;
|
||||
collection: RepositoryCollection;
|
||||
namespaces: NamespaceCollection;
|
||||
page: number;
|
||||
namespace: string;
|
||||
reposLink: string;
|
||||
namespacesLink: string;
|
||||
|
||||
// dispatched functions
|
||||
fetchReposByPage: (link: string, page: number, namespace?: string, filter?: string) => void;
|
||||
fetchNamespaces: (link: string) => void;
|
||||
};
|
||||
|
||||
class Overview extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
const { fetchReposByPage, reposLink, namespace, page, location } = this.props;
|
||||
fetchReposByPage(reposLink, page, namespace, urls.getQueryStringFromLocation(location));
|
||||
const { fetchReposByPage, fetchNamespaces, namespacesLink, namespace, page, location } = this.props;
|
||||
fetchNamespaces(namespacesLink);
|
||||
const link = this.getReposLink();
|
||||
if (link) {
|
||||
fetchReposByPage(link, page, namespace, urls.getQueryStringFromLocation(location));
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate = (prevProps: Props) => {
|
||||
const { loading, collection, namespace, page, reposLink, location, fetchReposByPage } = this.props;
|
||||
if (collection && page && !loading) {
|
||||
const { loading, collection, namespaces, namespace, page, location, fetchReposByPage } = this.props;
|
||||
if (!collection && namespace && prevProps.namespaces !== namespaces) {
|
||||
const link = this.getReposLink();
|
||||
fetchReposByPage(link, page, namespace, urls.getQueryStringFromLocation(location));
|
||||
} else if (collection && page && !loading) {
|
||||
const statePage: number = collection.page + 1;
|
||||
if (page !== statePage || prevProps.location.search !== location.search) {
|
||||
fetchReposByPage(reposLink, page, namespace, urls.getQueryStringFromLocation(location));
|
||||
const link = this.getReposLink();
|
||||
if (link) {
|
||||
fetchReposByPage(link, page, namespace, urls.getQueryStringFromLocation(location));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getReposLink = () => {
|
||||
const { namespace, namespaces, reposLink } = this.props;
|
||||
if (namespace) {
|
||||
return namespaces?.find(n => n.namespace === namespace)?._links?.repositories?.href;
|
||||
} else {
|
||||
return reposLink;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { error, loading, showCreateButton, namespace, t } = this.props;
|
||||
|
||||
@@ -134,26 +159,33 @@ class Overview extends React.Component<Props> {
|
||||
const mapStateToProps = (state: any, ownProps: Props) => {
|
||||
const { match } = ownProps;
|
||||
const collection = getRepositoryCollection(state);
|
||||
const loading = isFetchReposPending(state);
|
||||
const namespaces = getNamespaceCollection(state);
|
||||
const loading = isFetchReposPending(state) || isFetchNamespacesPending(state);
|
||||
const error = getFetchReposFailure(state);
|
||||
const { namespace, page } = urls.getNamespaceAndPageFromMatch(match);
|
||||
const showCreateButton = isAbleToCreateRepos(state);
|
||||
const reposLink = getRepositoriesLink(state);
|
||||
const namespacesLink = getNamespacesLink(state);
|
||||
return {
|
||||
collection,
|
||||
namespaces,
|
||||
loading,
|
||||
error,
|
||||
page,
|
||||
namespace,
|
||||
showCreateButton,
|
||||
reposLink
|
||||
reposLink,
|
||||
namespacesLink
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
return {
|
||||
fetchReposByPage: (link: string, page: number, namespace?: string, filter?: string) => {
|
||||
dispatch(fetchReposByPage(link, page, namespace, filter));
|
||||
fetchReposByPage: (link: string, page: number, filter?: string) => {
|
||||
dispatch(fetchReposByPage(link, page, filter));
|
||||
},
|
||||
fetchNamespaces: (link: string) => {
|
||||
dispatch(fetchNamespaces(link));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
import { apiClient } from "@scm-manager/ui-components";
|
||||
import * as types from "../../modules/types";
|
||||
import { Action, Repository, RepositoryCollection, RepositoryCreation } from "@scm-manager/ui-types";
|
||||
import { Action, Repository, RepositoryCollection, RepositoryCreation, NamespaceCollection } from "@scm-manager/ui-types";
|
||||
import { isPending } from "../../modules/pending";
|
||||
import { getFailure } from "../../modules/failure";
|
||||
|
||||
@@ -33,6 +33,11 @@ export const FETCH_REPOS_PENDING = `${FETCH_REPOS}_${types.PENDING_SUFFIX}`;
|
||||
export const FETCH_REPOS_SUCCESS = `${FETCH_REPOS}_${types.SUCCESS_SUFFIX}`;
|
||||
export const FETCH_REPOS_FAILURE = `${FETCH_REPOS}_${types.FAILURE_SUFFIX}`;
|
||||
|
||||
export const FETCH_NAMESPACES = "scm/repos/FETCH_NAMESPACES";
|
||||
export const FETCH_NAMESPACES_PENDING = `${FETCH_NAMESPACES}_${types.PENDING_SUFFIX}`;
|
||||
export const FETCH_NAMESPACES_SUCCESS = `${FETCH_NAMESPACES}_${types.SUCCESS_SUFFIX}`;
|
||||
export const FETCH_NAMESPACES_FAILURE = `${FETCH_NAMESPACES}_${types.FAILURE_SUFFIX}`;
|
||||
|
||||
export const FETCH_REPO = "scm/repos/FETCH_REPO";
|
||||
export const FETCH_REPO_PENDING = `${FETCH_REPO}_${types.PENDING_SUFFIX}`;
|
||||
export const FETCH_REPO_SUCCESS = `${FETCH_REPO}_${types.SUCCESS_SUFFIX}`;
|
||||
@@ -67,11 +72,10 @@ export function fetchRepos(link: string) {
|
||||
return fetchReposByLink(link);
|
||||
}
|
||||
|
||||
export function fetchReposByPage(link: string, page: number, namespace?: string, filter?: string) {
|
||||
const namespacePath = namespace ? `${namespace}/` : "";
|
||||
const linkWithPage = `${link}${namespacePath}?page=${page - 1}`;
|
||||
export function fetchReposByPage(link: string, page: number, filter?: string) {
|
||||
const linkWithPage = `${link}?page=${page - 1}`;
|
||||
if (filter) {
|
||||
return fetchReposByLink(`${linkWithPage}}&q=${decodeURIComponent(filter)}`);
|
||||
return fetchReposByLink(`${linkWithPage}&q=${decodeURIComponent(filter)}`);
|
||||
}
|
||||
return fetchReposByLink(linkWithPage);
|
||||
}
|
||||
@@ -125,6 +129,42 @@ export function fetchReposFailure(err: Error): Action {
|
||||
};
|
||||
}
|
||||
|
||||
// fetch namespaces
|
||||
export function fetchNamespaces(link: string) {
|
||||
return function(dispatch: any) {
|
||||
dispatch(fetchNamespacesPending());
|
||||
return apiClient
|
||||
.get(link)
|
||||
.then(response => response.json())
|
||||
.then(namespaces => {
|
||||
dispatch(fetchNamespacesSuccess(namespaces));
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(fetchNamespacesFailure(err));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchNamespacesPending(): Action {
|
||||
return {
|
||||
type: FETCH_NAMESPACES_PENDING
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchNamespacesSuccess(namespaces: NamespaceCollection): Action {
|
||||
return {
|
||||
type: FETCH_NAMESPACES_SUCCESS,
|
||||
payload: namespaces
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchNamespacesFailure(err: Error): Action {
|
||||
return {
|
||||
type: FETCH_NAMESPACES_FAILURE,
|
||||
payload: err
|
||||
};
|
||||
}
|
||||
|
||||
// fetch repo
|
||||
export function fetchRepoByLink(repo: Repository) {
|
||||
return fetchRepo(repo._links.self.href, repo.namespace, repo.name);
|
||||
@@ -348,7 +388,7 @@ function createIdentifier(repository: Repository) {
|
||||
return repository.namespace + "/" + repository.name;
|
||||
}
|
||||
|
||||
function normalizeByNamespaceAndName(repositoryCollection: RepositoryCollection) {
|
||||
function normalizeByNamespaceAndName(state: object, repositoryCollection: RepositoryCollection) {
|
||||
const names = [];
|
||||
const byNames = {};
|
||||
for (const repository of repositoryCollection._embedded.repositories) {
|
||||
@@ -357,6 +397,7 @@ function normalizeByNamespaceAndName(repositoryCollection: RepositoryCollection)
|
||||
byNames[identifier] = repository;
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
list: {
|
||||
...repositoryCollection,
|
||||
_embedded: {
|
||||
@@ -378,6 +419,13 @@ const reducerByNames = (state: object, repository: Repository) => {
|
||||
};
|
||||
};
|
||||
|
||||
const reducerForNamespaces = (state: object, namespaces: NamespaceCollection) => {
|
||||
return {
|
||||
...state,
|
||||
namespaces: namespaces._embedded
|
||||
};
|
||||
};
|
||||
|
||||
export default function reducer(
|
||||
state: object = {},
|
||||
action: Action = {
|
||||
@@ -390,7 +438,9 @@ export default function reducer(
|
||||
|
||||
switch (action.type) {
|
||||
case FETCH_REPOS_SUCCESS:
|
||||
return normalizeByNamespaceAndName(action.payload);
|
||||
return normalizeByNamespaceAndName(state, action.payload);
|
||||
case FETCH_NAMESPACES_SUCCESS:
|
||||
return reducerForNamespaces(state, action.payload);
|
||||
case FETCH_REPO_SUCCESS:
|
||||
return reducerByNames(state, action.payload);
|
||||
default:
|
||||
@@ -408,6 +458,7 @@ export function getRepositoryCollection(state: object) {
|
||||
}
|
||||
return {
|
||||
...state.repos.list,
|
||||
...state.repos.namespaces,
|
||||
_embedded: {
|
||||
repositories
|
||||
}
|
||||
@@ -415,6 +466,10 @@ export function getRepositoryCollection(state: object) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getNamespaceCollection(state: object) {
|
||||
return state.repos.namespaces?.namespaces;
|
||||
}
|
||||
|
||||
export function isFetchReposPending(state: object) {
|
||||
return isPending(state, FETCH_REPOS);
|
||||
}
|
||||
@@ -429,6 +484,20 @@ export function getRepository(state: object, namespace: string, name: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function isFetchNamespacesPending(state: object) {
|
||||
return isPending(state, FETCH_NAMESPACES);
|
||||
}
|
||||
|
||||
export function getFetchNamespacesFailure(state: object) {
|
||||
return getFailure(state, FETCH_NAMESPACES);
|
||||
}
|
||||
|
||||
export function getNamespace(state: object, namespace: string) {
|
||||
if (state.namespaces) {
|
||||
return state.namespaces[namespace];
|
||||
}
|
||||
}
|
||||
|
||||
export function isFetchRepoPending(state: object, namespace: string, name: string) {
|
||||
return isPending(state, FETCH_REPO, namespace + "/" + name);
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ public class IndexDtoGenerator extends HalAppenderMapper {
|
||||
builder.single(link("config", resourceLinks.config().self()));
|
||||
}
|
||||
builder.single(link("repositories", resourceLinks.repositoryCollection().self()));
|
||||
builder.single(link("namespaces", resourceLinks.namespaceCollection().self()));
|
||||
if (PermissionPermissions.list().isPermitted()) {
|
||||
builder.single(link("permissions", resourceLinks.permissions().self()));
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ package sonia.scm.api.v2.resources;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static de.otto.edison.hal.Link.link;
|
||||
import static de.otto.edison.hal.Links.linkingTo;
|
||||
|
||||
class NamespaceToNamespaceDtoMapper {
|
||||
@@ -38,6 +39,12 @@ class NamespaceToNamespaceDtoMapper {
|
||||
}
|
||||
|
||||
NamespaceDto map(String namespace) {
|
||||
return new NamespaceDto(namespace, linkingTo().self(links.namespace().self(namespace)).build());
|
||||
return new NamespaceDto(
|
||||
namespace,
|
||||
linkingTo()
|
||||
.self(links.namespace().self(namespace))
|
||||
.single(link("repositories", links.repositoryCollection().forNamespace(namespace)))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,5 +911,9 @@ class ResourceLinks {
|
||||
String self(String namespace) {
|
||||
return namespaceLinkBuilder.method("getNamespaceResource").parameters().method("get").parameters(namespace).href();
|
||||
}
|
||||
|
||||
String repositories(String namespace) {
|
||||
return namespaceLinkBuilder.method("getNamespaceResource").parameters().method("get").parameters(namespace).href();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user