2021-02-24 08:17:40 +01:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
import { File, Link, Repository } from "@scm-manager/ui-types";
|
|
|
|
|
import { requiredLink } from "./links";
|
2021-11-10 10:10:17 +01:00
|
|
|
import { apiClient } from "./apiclient";
|
|
|
|
|
import * as urls from "./urls";
|
2021-02-24 08:17:40 +01:00
|
|
|
import { useInfiniteQuery } from "react-query";
|
|
|
|
|
import { repoQueryKey } from "./keys";
|
|
|
|
|
import { useEffect } from "react";
|
2022-02-15 10:59:32 +01:00
|
|
|
import { createQueryString } from "./utils";
|
2021-02-24 08:17:40 +01:00
|
|
|
|
|
|
|
|
export type UseSourcesOptions = {
|
|
|
|
|
revision?: string;
|
|
|
|
|
path?: string;
|
|
|
|
|
refetchPartialInterval?: number;
|
|
|
|
|
enabled?: boolean;
|
2022-02-15 10:59:32 +01:00
|
|
|
collapse?: boolean;
|
2021-02-24 08:17:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const UseSourcesDefaultOptions: UseSourcesOptions = {
|
|
|
|
|
enabled: true,
|
2021-11-04 09:16:08 +01:00
|
|
|
refetchPartialInterval: 3000,
|
2022-02-15 10:59:32 +01:00
|
|
|
collapse: true
|
2021-02-24 08:17:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useSources = (repository: Repository, opts: UseSourcesOptions = UseSourcesDefaultOptions) => {
|
|
|
|
|
const options = {
|
|
|
|
|
...UseSourcesDefaultOptions,
|
2021-11-04 09:16:08 +01:00
|
|
|
...opts,
|
2021-02-24 08:17:40 +01:00
|
|
|
};
|
|
|
|
|
const link = createSourcesLink(repository, options);
|
|
|
|
|
const { isLoading, error, data, isFetchingNextPage, fetchNextPage, refetch } = useInfiniteQuery<File, Error, File>(
|
2022-02-15 10:59:32 +01:00
|
|
|
repoQueryKey(repository, "sources", options.revision || "", options.path || "", options.collapse ? "collapse" : ""),
|
2021-02-24 08:17:40 +01:00
|
|
|
({ pageParam }) => {
|
2021-11-04 09:16:08 +01:00
|
|
|
return apiClient.get(pageParam || link).then((response) => response.json());
|
2021-02-24 08:17:40 +01:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
enabled: options.enabled,
|
2021-11-04 09:16:08 +01:00
|
|
|
getNextPageParam: (lastPage) => {
|
2021-02-24 08:17:40 +01:00
|
|
|
return (lastPage._links.proceed as Link)?.href;
|
2021-11-04 09:16:08 +01:00
|
|
|
},
|
2021-02-24 08:17:40 +01:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const file = merge(data?.pages);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const intervalId = setInterval(() => {
|
|
|
|
|
if (isPartial(file)) {
|
|
|
|
|
refetch({
|
2021-11-04 09:16:08 +01:00
|
|
|
throwOnError: true,
|
2021-02-24 08:17:40 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}, options.refetchPartialInterval);
|
|
|
|
|
return () => clearInterval(intervalId);
|
2022-06-22 11:49:26 +02:00
|
|
|
}, [options.refetchPartialInterval, file, refetch]);
|
2021-02-24 08:17:40 +01:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
isLoading,
|
|
|
|
|
error,
|
|
|
|
|
data: file,
|
|
|
|
|
isFetchingNextPage,
|
|
|
|
|
fetchNextPage: () => {
|
|
|
|
|
// wrapped because we do not want to leak react-query types in our api
|
|
|
|
|
fetchNextPage();
|
2021-11-04 09:16:08 +01:00
|
|
|
},
|
2021-02-24 08:17:40 +01:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const createSourcesLink = (repository: Repository, options: UseSourcesOptions) => {
|
|
|
|
|
let link = requiredLink(repository, "sources");
|
|
|
|
|
if (options.revision) {
|
|
|
|
|
link = urls.concat(link, encodeURIComponent(options.revision));
|
|
|
|
|
|
|
|
|
|
if (options.path) {
|
2022-09-09 08:19:04 +02:00
|
|
|
link = urls.concat(link, encodeInvalidCharacters(options.path));
|
2021-02-24 08:17:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-02-15 10:59:32 +01:00
|
|
|
if (options.collapse) {
|
|
|
|
|
return `${link}?${createQueryString({ collapse: "true" })}`;
|
|
|
|
|
}
|
2021-02-24 08:17:40 +01:00
|
|
|
return link;
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-09 08:19:04 +02:00
|
|
|
const encodeInvalidCharacters = (input: string) => input.replace(/\[/g, "%5B").replace(/]/g, "%5D");
|
|
|
|
|
|
2021-02-24 08:17:40 +01:00
|
|
|
const merge = (files?: File[]): File | undefined => {
|
|
|
|
|
if (!files || files.length === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const children = [];
|
|
|
|
|
for (const page of files) {
|
|
|
|
|
children.push(...(page._embedded?.children || []));
|
|
|
|
|
}
|
|
|
|
|
const lastPage = files[files.length - 1];
|
|
|
|
|
return {
|
|
|
|
|
...lastPage,
|
|
|
|
|
_embedded: {
|
|
|
|
|
...lastPage._embedded,
|
2021-11-04 09:16:08 +01:00
|
|
|
children,
|
|
|
|
|
},
|
2021-02-24 08:17:40 +01:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const isFilePartial = (f: File) => {
|
|
|
|
|
return f.partialResult && !f.computationAborted;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const isPartial = (file?: File) => {
|
|
|
|
|
if (!file) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (isFilePartial(file)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return file._embedded?.children?.some(isFilePartial);
|
|
|
|
|
};
|