This commit is contained in:
Rene Pfeuffer
2020-02-20 14:36:13 +01:00
parent 4bc3d16aa9
commit c4a801a7be
5 changed files with 137 additions and 78 deletions

View File

@@ -112,10 +112,11 @@ public final class BrowseCommandRequest extends FileBaseCommandRequest
final BrowseCommandRequest other = (BrowseCommandRequest) obj;
return super.equals(obj) && Objects.equal(recursive, other.recursive)
return super.equals(obj)
&& Objects.equal(recursive, other.recursive)
&& Objects.equal(disableLastCommit, other.disableLastCommit)
&& Objects.equal(disableSubRepositoryDetection,
other.disableSubRepositoryDetection);
&& Objects.equal(disableSubRepositoryDetection, other.disableSubRepositoryDetection)
&& Objects.equal(offset, other.offset);
}
/**
@@ -128,7 +129,7 @@ public final class BrowseCommandRequest extends FileBaseCommandRequest
public int hashCode()
{
return Objects.hashCode(super.hashCode(), recursive, disableLastCommit,
disableSubRepositoryDetection);
disableSubRepositoryDetection, offset);
}
/**
@@ -147,6 +148,7 @@ public final class BrowseCommandRequest extends FileBaseCommandRequest
.add("recursive", recursive)
.add("disableLastCommit", disableLastCommit)
.add("disableSubRepositoryDetection", disableSubRepositoryDetection)
.add("offset", offset)
.toString();
//J+
}

View File

@@ -16,9 +16,9 @@ export type File = {
length?: number;
commitDate?: string;
subRepository?: SubRepository; // TODO
partialResult: boolean;
computationAborted: boolean;
truncated: boolean;
partialResult?: boolean;
computationAborted?: boolean;
truncated?: boolean;
_links: Links;
_embedded: {
children: File[] | null | undefined;

View File

@@ -12,7 +12,7 @@ import {
getFetchSourcesFailure,
getHunkCount,
getSources,
isFetchSourcesPending, isUpdateSourcePending
isFetchSourcesPending
} from "../modules/sources";
import FileTreeLeaf from "./FileTreeLeaf";
import Button from "@scm-manager/ui-components/src/buttons/Button";
@@ -86,7 +86,7 @@ class FileTree extends React.Component<Props, State> {
}
loadMore = () => {
// console.log("smth");
this.props.fetchSources(this.props.repository, this.props.revision, this.props.path, this.props.hunks.length);
};
render() {
@@ -124,22 +124,6 @@ class FileTree extends React.Component<Props, State> {
});
}
const compareFiles = function(f1: File, f2: File): number {
if (f1.directory) {
if (f2.directory) {
return f1.name.localeCompare(f2.name);
} else {
return -1;
}
} else {
if (f2.directory) {
return 1;
} else {
return f1.name.localeCompare(f2.name);
}
}
};
hunks
.filter(hunk => !hunk.loading)
.forEach(hunk => {
@@ -149,7 +133,9 @@ class FileTree extends React.Component<Props, State> {
}
});
if (files && files.length > 0) {
const loading = hunks.filter(hunk => hunk.loading).length > 0;
if (loading || (files && files.length > 0)) {
let baseUrlWithRevision = baseUrl;
if (revision) {
baseUrlWithRevision += "/" + encodeURIComponent(revision);
@@ -195,7 +181,6 @@ const mapDispatchToProps = (dispatch: any, ownProps: Props) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository, revision, path } = ownProps;
const loading = isFetchSourcesPending(state, repository, revision, path, 0);
const error = getFetchSourcesFailure(state, repository, revision, path, 0);
const hunkCount = getHunkCount(state, repository, revision, path);
const hunks = [];
@@ -212,7 +197,6 @@ const mapStateToProps = (state: any, ownProps: Props) => {
return {
revision,
path,
loading,
error,
hunks
};

View File

@@ -37,6 +37,9 @@ const collection = {
length: 176,
revision: "76aae4bb4ceacf0e88938eb5b6832738b7d537b4",
subRepository: undefined,
truncated: true,
partialResult: false,
computationAborted: false,
_links: {
self: {
href:
@@ -120,12 +123,23 @@ describe("sources fetch", () => {
const expectedActions = [
{
type: FETCH_SOURCES_PENDING,
itemId: "scm/core/_/"
itemId: "scm/core/_//",
payload: {
hunk: 0,
updatePending: false,
pending: true,
sources: {}
}
},
{
type: FETCH_SOURCES_SUCCESS,
itemId: "scm/core/_/",
payload: { updatePending: false, sources: collection }
itemId: "scm/core/_//",
payload: {
hunk: 0,
updatePending: false,
pending: false,
sources: collection
}
}
];
@@ -136,17 +150,28 @@ describe("sources fetch", () => {
});
it("should fetch the sources of the repository with the given revision and path", () => {
fetchMock.getOnce(sourcesUrl + "abc/src", collection);
fetchMock.getOnce(sourcesUrl + "abc/src?offset=0", collection);
const expectedActions = [
{
type: FETCH_SOURCES_PENDING,
itemId: "scm/core/abc/src"
itemId: "scm/core/abc/src/",
payload: {
hunk: 0,
updatePending: false,
pending: true,
sources: {}
}
},
{
type: FETCH_SOURCES_SUCCESS,
itemId: "scm/core/abc/src",
payload: { updatePending: false, sources: collection }
itemId: "scm/core/abc/src/",
payload: {
hunk: 0,
updatePending: false,
pending: false,
sources: collection
}
}
];
@@ -166,7 +191,7 @@ describe("sources fetch", () => {
const actions = store.getActions();
expect(actions[0].type).toBe(FETCH_SOURCES_PENDING);
expect(actions[1].type).toBe(FETCH_SOURCES_FAILURE);
expect(actions[1].itemId).toBe("scm/core/_/");
expect(actions[1].itemId).toBe("scm/core/_//");
expect(actions[1].payload).toBeDefined();
});
});
@@ -180,16 +205,18 @@ describe("reducer tests", () => {
it("should store the collection, without revision and path", () => {
const expectedState = {
"scm/core/_/": { updatePending: false, sources: collection }
"scm/core/_//0": { pending: false, updatePending: false, sources: collection },
"scm/core/_//hunkCount": 1
};
expect(reducer({}, fetchSourcesSuccess(repository, "", "", collection))).toEqual(expectedState);
expect(reducer({}, fetchSourcesSuccess(repository, "", "", 0, collection))).toEqual(expectedState);
});
it("should store the collection, with revision and path", () => {
const expectedState = {
"scm/core/abc/src/main": { updatePending: false, sources: collection }
"scm/core/abc/src/main/0": { pending: false, updatePending: false, sources: collection },
"scm/core/abc/src/main/hunkCount": 1
};
expect(reducer({}, fetchSourcesSuccess(repository, "abc", "src/main", collection))).toEqual(expectedState);
expect(reducer({}, fetchSourcesSuccess(repository, "abc", "src/main", 0, collection))).toEqual(expectedState);
});
});
@@ -197,7 +224,7 @@ describe("selector tests", () => {
it("should return false if it is no directory", () => {
const state = {
sources: {
"scm/core/abc/src/main/package.json": {
"scm/core/abc/src/main/package.json/0": {
sources: { noDirectory }
}
}
@@ -208,7 +235,7 @@ describe("selector tests", () => {
it("should return true if it is directory", () => {
const state = {
sources: {
"scm/core/abc/src": noDirectory
"scm/core/abc/src/0": noDirectory
}
};
expect(isDirectory(state, repository, "abc", "src")).toBe(true);
@@ -221,7 +248,7 @@ describe("selector tests", () => {
it("should return the source collection without revision and path", () => {
const state = {
sources: {
"scm/core/_/": {
"scm/core/_//0": {
sources: collection
}
}
@@ -232,7 +259,7 @@ describe("selector tests", () => {
it("should return the source collection with revision and path", () => {
const state = {
sources: {
"scm/core/abc/src/main": {
"scm/core/abc/src/main/0": {
sources: collection
}
}
@@ -242,15 +269,26 @@ describe("selector tests", () => {
it("should return true, when fetch sources is pending", () => {
const state = {
pending: {
[FETCH_SOURCES + "/scm/core/_/"]: true
sources: {
"scm/core/_//0": {
pending: true,
sources: {}
}
}
};
expect(isFetchSourcesPending(state, repository, "", "")).toEqual(true);
expect(isFetchSourcesPending(state, repository, "", "", 0)).toEqual(true);
});
it("should return false, when fetch sources is not pending", () => {
expect(isFetchSourcesPending({}, repository, "", "")).toEqual(false);
const state = {
sources: {
"scm/core/_//0": {
pending: false,
sources: {}
}
}
};
expect(isFetchSourcesPending(state, repository, "", "", 0)).toEqual(false);
});
const error = new Error("incredible error from hell");
@@ -258,13 +296,13 @@ describe("selector tests", () => {
it("should return error when fetch sources did fail", () => {
const state = {
failure: {
[FETCH_SOURCES + "/scm/core/_/"]: error
[FETCH_SOURCES + "/scm/core/_//"]: error
}
};
expect(getFetchSourcesFailure(state, repository, "", "")).toEqual(error);
expect(getFetchSourcesFailure(state, repository, "", "", 0)).toEqual(error);
});
it("should return undefined when fetch sources did not fail", () => {
expect(getFetchSourcesFailure({}, repository, "", "")).toBe(undefined);
expect(getFetchSourcesFailure({}, repository, "", "", 0)).toBe(undefined);
});
});

View File

@@ -1,7 +1,6 @@
import * as types from "../../../modules/types";
import { Action, File, Link, Repository } from "@scm-manager/ui-types";
import { apiClient } from "@scm-manager/ui-components";
import { isPending } from "../../../modules/pending";
import { getFailure } from "../../../modules/failure";
export const FETCH_SOURCES = "scm/repos/FETCH_SOURCES";
@@ -27,8 +26,18 @@ export function fetchSources(repository: Repository, revision: string, path: str
updateSourcesPending(repository, revision, path, hunk, getSources(state, repository, revision, path, hunk))
);
}
let offset = 0;
const hunkCount = getHunkCount(state, repository, revision, path);
for (let i = 0; i < hunkCount; ++i) {
const sources = getSources(state, repository, revision, path, i);
if (sources?._embedded.children) {
offset += sources._embedded.children.length;
}
}
return apiClient
.get(createUrl(repository, revision, path, hunk))
.get(createUrl(repository, revision, path, offset))
.then(response => response.json())
.then((sources: File) => {
dispatch(fetchSourcesSuccess(repository, revision, path, hunk, sources));
@@ -39,7 +48,7 @@ export function fetchSources(repository: Repository, revision: string, path: str
};
}
function createUrl(repository: Repository, revision: string, path: string, hunk: number) {
function createUrl(repository: Repository, revision: string, path: string, offset: number) {
const base = (repository._links.sources as Link).href;
if (!revision && !path) {
return base;
@@ -47,14 +56,14 @@ function createUrl(repository: Repository, revision: string, path: string, hunk:
// TODO handle trailing slash
const pathDefined = path ? path : "";
return `${base}${encodeURIComponent(revision)}/${pathDefined}?hunk=${hunk}`;
return `${base}${encodeURIComponent(revision)}/${pathDefined}?offset=${offset}`;
}
export function fetchSourcesPending(repository: Repository, revision: string, path: string, hunk: number): Action {
return {
type: FETCH_SOURCES_PENDING,
itemId: createItemId(repository, revision, path),
payload: { hunk, pending: true, sources: {} }
itemId: createItemId(repository, revision, path, ""),
payload: { hunk, pending: true, updatePending: false, sources: {} }
};
}
@@ -63,12 +72,12 @@ export function updateSourcesPending(
revision: string,
path: string,
hunk: number,
currentSources: any
currentSources: File
): Action {
return {
type: FETCH_UPDATES_PENDING,
payload: { hunk, updatePending: true, sources: currentSources },
itemId: createItemId(repository, revision, path)
payload: { hunk, pending: false, updatePending: true, sources: currentSources },
itemId: createItemId(repository, revision, path, "")
};
}
@@ -82,7 +91,7 @@ export function fetchSourcesSuccess(
return {
type: FETCH_SOURCES_SUCCESS,
payload: { hunk, pending: false, updatePending: false, sources },
itemId: createItemId(repository, revision, path)
itemId: createItemId(repository, revision, path, "")
};
}
@@ -96,14 +105,14 @@ export function fetchSourcesFailure(
return {
type: FETCH_SOURCES_FAILURE,
payload: error,
itemId: createItemId(repository, revision, path)
itemId: createItemId(repository, revision, path, "")
};
}
function createItemId(repository: Repository, revision: string | undefined, path: string) {
function createItemId(repository: Repository, revision: string | undefined, path: string, hunk: number | string) {
const revPart = revision ? revision : "_";
const pathPart = path ? path : "";
return `${repository.namespace}/${repository.name}/${decodeURIComponent(revPart)}/${pathPart}`;
return `${repository.namespace}/${repository.name}/${decodeURIComponent(revPart)}/${pathPart}/${hunk}`;
}
// reducer
@@ -114,18 +123,38 @@ export default function reducer(
type: "UNKNOWN"
}
): any {
if (action.itemId && (action.type === FETCH_SOURCES_SUCCESS || action.type === FETCH_UPDATES_PENDING)) {
console.log("adding payload to " + action.itemId + "/" + action.payload.hunk);
if (action.itemId && action.type === FETCH_SOURCES_SUCCESS) {
return {
...state,
[action.itemId + "/hunkCount"]: action.payload.hunk + 1,
[action.itemId + "/" + action.payload.hunk]: {
[action.itemId + "hunkCount"]: action.payload.hunk + 1,
[action.itemId + action.payload.hunk]: {
sources: action.payload.sources,
loading: false
updatePending: false,
pending: false
}
};
} else if (action.itemId && action.type === FETCH_UPDATES_PENDING) {
return {
...state,
[action.itemId + "hunkCount"]: action.payload.hunk + 1,
[action.itemId + action.payload.hunk]: {
sources: action.payload.sources,
updatePending: true,
pending: false
}
};
} else if (action.itemId && action.type === FETCH_SOURCES_PENDING) {
return {
...state,
[action.itemId + "hunkCount"]: action.payload.hunk + 1,
[action.itemId + action.payload.hunk]: {
updatePending: false,
pending: true
}
};
} else {
return state;
}
return state;
}
// selectors
@@ -141,7 +170,7 @@ export function isDirectory(state: any, repository: Repository, revision: string
export function getHunkCount(state: any, repository: Repository, revision: string | undefined, path: string): number {
if (state.sources) {
const count = state.sources[createItemId(repository, revision, path) + "/hunkCount"];
const count = state.sources[createItemId(repository, revision, path, "hunkCount")];
return count ? count : 0;
}
return 0;
@@ -152,10 +181,10 @@ export function getSources(
repository: Repository,
revision: string | undefined,
path: string,
hunk: number
hunk = 0
): File | null | undefined {
if (state.sources) {
return state.sources[createItemId(repository, revision, path) + "/" + hunk]?.sources;
return state.sources[createItemId(repository, revision, path, hunk)]?.sources;
}
return null;
}
@@ -165,9 +194,12 @@ export function isFetchSourcesPending(
repository: Repository,
revision: string,
path: string,
hunk: number
hunk = 0
): boolean {
return state && isPending(state, FETCH_SOURCES, createItemId(repository, revision, path));
if (state.sources) {
return state.sources[createItemId(repository, revision, path, hunk)]?.pending;
}
return false;
}
export function isUpdateSourcePending(
@@ -177,7 +209,10 @@ export function isUpdateSourcePending(
path: string,
hunk: number
): boolean {
return state?.sources && state.sources[createItemId(repository, revision, path) + "/" + hunk]?.updatePending;
if (state.sources) {
return state.sources[createItemId(repository, revision, path, hunk)]?.updatePending;
}
return false;
}
export function getFetchSourcesFailure(
@@ -185,7 +220,7 @@ export function getFetchSourcesFailure(
repository: Repository,
revision: string,
path: string,
hunk: number
hunk = 0
): Error | null | undefined {
return getFailure(state, FETCH_SOURCES, createItemId(repository, revision, path));
return getFailure(state, FETCH_SOURCES, createItemId(repository, revision, path, ""));
}