@databiosphere/findable-ui 35.1.0 → 35.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +12 -0
- package/lib/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestDownload/fileManifestDownload.js +21 -29
- package/lib/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestSpreadsheet/fileManifestSpreadsheet.js +21 -36
- package/lib/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/constants.d.ts +2 -0
- package/lib/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/constants.js +22 -0
- package/lib/components/Table/components/TableCell/components/CodeCell/codeCell.d.ts +3 -0
- package/lib/components/Table/components/TableCell/components/CodeCell/codeCell.js +9 -0
- package/lib/components/Table/components/TableCell/components/CodeCell/codeCell.styles.d.ts +5 -0
- package/lib/components/Table/components/TableCell/components/CodeCell/codeCell.styles.js +15 -0
- package/lib/hooks/useFileManifest/useFileManifestDownload.d.ts +2 -2
- package/lib/hooks/useFileManifest/useFileManifestDownload.js +3 -10
- package/lib/hooks/useFileManifest/useFileManifestSpreadsheet.d.ts +5 -4
- package/lib/hooks/useFileManifest/useFileManifestSpreadsheet.js +24 -20
- package/package.json +1 -1
- package/src/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestDownload/fileManifestDownload.tsx +43 -71
- package/src/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestSpreadsheet/fileManifestSpreadsheet.tsx +52 -74
- package/src/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/constants.ts +24 -0
- package/src/components/Table/components/TableCell/components/CodeCell/codeCell.styles.ts +16 -0
- package/src/components/Table/components/TableCell/components/CodeCell/codeCell.tsx +21 -0
- package/src/hooks/useFileManifest/useFileManifestDownload.ts +9 -16
- package/src/hooks/useFileManifest/useFileManifestSpreadsheet.ts +41 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [35.2.0](https://github.com/DataBiosphere/findable-ui/compare/v35.1.0...v35.2.0) (2025-06-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add table <code> element ([#525](https://github.com/DataBiosphere/findable-ui/issues/525)) ([#527](https://github.com/DataBiosphere/findable-ui/issues/527)) ([02cb3b6](https://github.com/DataBiosphere/findable-ui/commit/02cb3b698b25a4295fc5ea2048541869301b918f))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* make user request project metadata by clicking the request link button ([#530](https://github.com/DataBiosphere/findable-ui/issues/530)) ([#531](https://github.com/DataBiosphere/findable-ui/issues/531)) ([b645e0f](https://github.com/DataBiosphere/findable-ui/commit/b645e0fe5604dfc7fc195f91747d4a7985b39e4d))
|
|
14
|
+
|
|
3
15
|
## [35.1.0](https://github.com/DataBiosphere/findable-ui/compare/v35.0.3...v35.1.0) (2025-06-05)
|
|
4
16
|
|
|
5
17
|
|
|
@@ -1,49 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Button, TableBody, TableCell, TableRow, Tooltip } from "@mui/material";
|
|
2
2
|
import copy from "copy-to-clipboard";
|
|
3
|
-
import React
|
|
3
|
+
import React from "react";
|
|
4
4
|
import { useDownloadStatus } from "../../../../../../../../hooks/useDownloadStatus";
|
|
5
5
|
import { useFileManifestDownload } from "../../../../../../../../hooks/useFileManifest/useFileManifestDownload";
|
|
6
6
|
import { useLoginGuard } from "../../../../../../../../providers/loginGuard/hook";
|
|
7
|
+
import { BUTTON_PROPS } from "../../../../../../../common/Button/constants";
|
|
7
8
|
import { ButtonGroup } from "../../../../../../../common/ButtonGroup/buttonGroup";
|
|
8
|
-
import { ButtonGroupButton } from "../../../../../../../common/ButtonGroup/components/ButtonGroupButton/buttonGroupButton";
|
|
9
9
|
import { ContentCopyIconSmall, DownloadIconSmall, } from "../../../../../../../common/CustomIcon/common/constants";
|
|
10
10
|
import { FluidPaper, GridPaper, } from "../../../../../../../common/Paper/paper.styles";
|
|
11
11
|
import { Loading, LOADING_PANEL_STYLE, } from "../../../../../../../Loading/loading";
|
|
12
12
|
import { GridTable } from "../../../../../../../Table/common/gridTable.styles";
|
|
13
|
+
import { TOOLTIP_PROPS } from "../../constants";
|
|
13
14
|
import { SectionTitle, TableContainer, } from "../../manifestDownloadEntity.styles";
|
|
14
15
|
export const FileManifestDownload = ({ filters, }) => {
|
|
15
|
-
const downloadRef = useRef(null);
|
|
16
16
|
const { disabled, message } = useDownloadStatus();
|
|
17
|
-
const { fileName, isIdle, isLoading, manifestURL } = useFileManifestDownload(filters
|
|
18
|
-
const isInProgress = (isIdle || isLoading) && !disabled;
|
|
19
|
-
const isReady = Boolean(manifestURL) || disabled;
|
|
17
|
+
const { fileName, isIdle, isLoading, manifestURL, requestManifest } = useFileManifestDownload(filters);
|
|
20
18
|
// Prompt user for login before download and copy, if required.
|
|
21
19
|
const { requireLogin } = useLoginGuard();
|
|
22
|
-
// Copies file manifest.
|
|
23
|
-
const copyManifestURL = (url) => {
|
|
24
|
-
if (!url)
|
|
25
|
-
return;
|
|
26
|
-
copy(url);
|
|
27
|
-
};
|
|
28
|
-
// Downloads file manifest.
|
|
29
|
-
const downloadManifestURL = () => {
|
|
30
|
-
downloadRef.current?.click();
|
|
31
|
-
};
|
|
32
20
|
return (React.createElement(FluidPaper, null,
|
|
33
21
|
React.createElement(GridPaper, null,
|
|
34
22
|
React.createElement(SectionTitle, null, "File Manifest"),
|
|
35
23
|
React.createElement(TableContainer, null,
|
|
36
|
-
React.createElement(Loading, { loading:
|
|
37
|
-
React.createElement(GridTable, { gridTemplateColumns:
|
|
24
|
+
React.createElement(Loading, { loading: isLoading, panelStyle: LOADING_PANEL_STYLE.INHERIT }),
|
|
25
|
+
React.createElement(GridTable, { gridTemplateColumns: "auto 1fr" },
|
|
38
26
|
React.createElement(TableBody, null,
|
|
39
|
-
React.createElement(TableRow, null,
|
|
40
|
-
React.createElement(
|
|
41
|
-
React.createElement(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
27
|
+
React.createElement(TableRow, null, isIdle || isLoading ? (React.createElement(TableCell, null,
|
|
28
|
+
React.createElement(Tooltip, { ...TOOLTIP_PROPS, title: message },
|
|
29
|
+
React.createElement("span", null,
|
|
30
|
+
React.createElement(Button, { ...BUTTON_PROPS.PRIMARY_CONTAINED, disabled: disabled || isLoading, onClick: () => requireLogin(requestManifest) }, "Request link"))))) : (React.createElement(React.Fragment, null,
|
|
31
|
+
manifestURL && (React.createElement(TableCell, null,
|
|
32
|
+
React.createElement(ButtonGroup, { Buttons: [
|
|
33
|
+
React.createElement(Button, { key: "download", download: true, href: manifestURL },
|
|
34
|
+
React.createElement(DownloadIconSmall, null)),
|
|
35
|
+
React.createElement(Button, { key: "copy", onClick: () => copy(manifestURL) },
|
|
36
|
+
React.createElement(ContentCopyIconSmall, null)),
|
|
37
|
+
] }))),
|
|
38
|
+
React.createElement(TableCell, null, manifestURL
|
|
39
|
+
? fileName
|
|
40
|
+
: "The manifest is not available for this project."))))))))));
|
|
49
41
|
};
|
|
@@ -1,53 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Button, TableBody, TableCell, TableRow, Tooltip } from "@mui/material";
|
|
2
2
|
import copy from "copy-to-clipboard";
|
|
3
|
-
import React
|
|
3
|
+
import React from "react";
|
|
4
4
|
import { useDownloadStatus } from "../../../../../../../../hooks/useDownloadStatus";
|
|
5
5
|
import { useFileManifestSpreadsheet } from "../../../../../../../../hooks/useFileManifest/useFileManifestSpreadsheet";
|
|
6
|
-
import {
|
|
6
|
+
import { BUTTON_PROPS } from "../../../../../../../common/Button/constants";
|
|
7
7
|
import { ButtonGroup } from "../../../../../../../common/ButtonGroup/buttonGroup";
|
|
8
|
-
import { ButtonGroupButton } from "../../../../../../../common/ButtonGroup/components/ButtonGroupButton/buttonGroupButton";
|
|
9
8
|
import { ContentCopyIconSmall, DownloadIconSmall, } from "../../../../../../../common/CustomIcon/common/constants";
|
|
10
9
|
import { FluidPaper, GridPaper, } from "../../../../../../../common/Paper/paper.styles";
|
|
11
10
|
import { Loading, LOADING_PANEL_STYLE, } from "../../../../../../../Loading/loading";
|
|
12
11
|
import { GridTable } from "../../../../../../../Table/common/gridTable.styles";
|
|
12
|
+
import { TOOLTIP_PROPS } from "../../constants";
|
|
13
13
|
import { SectionTitle, TableContainer, } from "../../manifestDownloadEntity.styles";
|
|
14
14
|
export const FileManifestSpreadsheet = ({ filters, }) => {
|
|
15
|
-
const downloadRef = useRef(null);
|
|
16
15
|
const { disabled, message } = useDownloadStatus();
|
|
17
|
-
const {
|
|
18
|
-
const { data, isLoading, run } = useRequestFileLocation(fileUrl);
|
|
19
|
-
const spreadsheetURL = data?.location;
|
|
20
|
-
const isInProgress = (exists === undefined || isLoading) && !disabled;
|
|
21
|
-
const isReady = Boolean(spreadsheetURL) || disabled;
|
|
22
|
-
// Copies metadata spreadsheet.
|
|
23
|
-
const copyMetadataURL = (url) => {
|
|
24
|
-
if (!url)
|
|
25
|
-
return;
|
|
26
|
-
copy(url);
|
|
27
|
-
};
|
|
28
|
-
// Downloads metadata spreadsheet.
|
|
29
|
-
const downloadMetadataURL = () => {
|
|
30
|
-
downloadRef.current?.click();
|
|
31
|
-
};
|
|
32
|
-
// Requests metadata spreadsheet.
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
run();
|
|
35
|
-
}, [fileUrl, run]);
|
|
16
|
+
const { fileName, isIdle = false, isLoading = false, requestManifest, spreadsheetUrl, } = useFileManifestSpreadsheet(filters) || {};
|
|
36
17
|
return (React.createElement(FluidPaper, null,
|
|
37
18
|
React.createElement(GridPaper, null,
|
|
38
19
|
React.createElement(SectionTitle, null, "Metadata"),
|
|
39
20
|
React.createElement(TableContainer, null,
|
|
40
|
-
React.createElement(Loading, { loading:
|
|
41
|
-
React.createElement(GridTable, { gridTemplateColumns:
|
|
21
|
+
React.createElement(Loading, { loading: isLoading, panelStyle: LOADING_PANEL_STYLE.INHERIT }),
|
|
22
|
+
React.createElement(GridTable, { gridTemplateColumns: "auto 1fr" },
|
|
42
23
|
React.createElement(TableBody, null,
|
|
43
|
-
React.createElement(TableRow, null,
|
|
44
|
-
React.createElement(
|
|
45
|
-
React.createElement(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
24
|
+
React.createElement(TableRow, null, isIdle || isLoading ? (React.createElement(TableCell, null,
|
|
25
|
+
React.createElement(Tooltip, { ...TOOLTIP_PROPS, title: message },
|
|
26
|
+
React.createElement("span", null,
|
|
27
|
+
React.createElement(Button, { ...BUTTON_PROPS.PRIMARY_CONTAINED, disabled: disabled || isLoading, onClick: () => requestManifest?.() }, "Request link"))))) : (React.createElement(React.Fragment, null,
|
|
28
|
+
spreadsheetUrl && (React.createElement(TableCell, null,
|
|
29
|
+
React.createElement(ButtonGroup, { Buttons: [
|
|
30
|
+
React.createElement(Button, { key: "download", download: true, href: spreadsheetUrl },
|
|
31
|
+
React.createElement(DownloadIconSmall, null)),
|
|
32
|
+
React.createElement(Button, { key: "copy", onClick: () => copy(spreadsheetUrl) },
|
|
33
|
+
React.createElement(ContentCopyIconSmall, null)),
|
|
34
|
+
] }))),
|
|
35
|
+
React.createElement(TableCell, null, spreadsheetUrl
|
|
36
|
+
? fileName
|
|
37
|
+
: "The metadata is not available for this project."))))))))));
|
|
53
38
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const TOOLTIP_PROPS = {
|
|
2
|
+
arrow: true,
|
|
3
|
+
slotProps: {
|
|
4
|
+
popper: {
|
|
5
|
+
modifiers: [
|
|
6
|
+
{
|
|
7
|
+
name: "offset",
|
|
8
|
+
options: {
|
|
9
|
+
offset: [0, -4],
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "preventOverflow",
|
|
14
|
+
options: { padding: 8 },
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
tooltip: {
|
|
19
|
+
sx: { maxWidth: "none" },
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CellContext, RowData } from "@tanstack/react-table";
|
|
2
|
+
import { BaseComponentProps } from "../../../../../types";
|
|
3
|
+
export declare const CodeCell: <T extends RowData, TValue extends string = string>({ className, getValue, }: BaseComponentProps & CellContext<T, TValue>) => JSX.Element | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CHIP_PROPS } from "../../../../../../styles/common/mui/chip";
|
|
3
|
+
import { StyledChip } from "./codeCell.styles";
|
|
4
|
+
export const CodeCell = ({ className, getValue, }) => {
|
|
5
|
+
const value = getValue();
|
|
6
|
+
if (!value)
|
|
7
|
+
return null;
|
|
8
|
+
return (React.createElement(StyledChip, { className: className, color: CHIP_PROPS.COLOR.DEFAULT, label: value, size: CHIP_PROPS.SIZE.SMALL }));
|
|
9
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const StyledChip: import("@emotion/styled").StyledComponent<import("@mui/material").ChipOwnProps & import("@mui/material/OverridableComponent").CommonProps & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
2
|
+
ref?: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLDivElement> | null | undefined;
|
|
3
|
+
}, "label" | "style" | "className" | "classes" | "tabIndex" | "color" | "children" | "sx" | "variant" | "disabled" | "size" | "avatar" | "clickable" | "deleteIcon" | "icon" | "onDelete" | "skipFocusWhenDisabled"> & {
|
|
4
|
+
theme?: import("@emotion/react").Theme;
|
|
5
|
+
}, {}, {}>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
import { Chip } from "@mui/material";
|
|
3
|
+
import { PALETTE } from "../../../../../../styles/common/constants/palette";
|
|
4
|
+
export const StyledChip = styled(Chip) `
|
|
5
|
+
border-radius: 4px;
|
|
6
|
+
box-shadow: 0 0 0 2px ${PALETTE.COMMON_WHITE};
|
|
7
|
+
height: auto;
|
|
8
|
+
justify-self: flex-start;
|
|
9
|
+
min-width: 0;
|
|
10
|
+
|
|
11
|
+
.MuiChip-label {
|
|
12
|
+
padding: 2px 8px;
|
|
13
|
+
white-space: normal;
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
@@ -4,11 +4,11 @@ export interface ManifestDownload {
|
|
|
4
4
|
isIdle: boolean;
|
|
5
5
|
isLoading: boolean;
|
|
6
6
|
manifestURL?: string;
|
|
7
|
+
requestManifest: () => void;
|
|
7
8
|
}
|
|
8
9
|
/**
|
|
9
10
|
* Returns file manifest download url and file name.
|
|
10
11
|
* @param filters - Filters.
|
|
11
|
-
* @param disabled - Disabled.
|
|
12
12
|
* @returns file manifest download url and file name.
|
|
13
13
|
*/
|
|
14
|
-
export declare const useFileManifestDownload: (filters: Filters
|
|
14
|
+
export declare const useFileManifestDownload: (filters: Filters) => ManifestDownload;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
1
|
import { MANIFEST_DOWNLOAD_FORMAT } from "../../apis/azul/common/entities";
|
|
3
2
|
import { BULK_DOWNLOAD_EXECUTION_ENVIRONMENT } from "../../components/Export/common/entities";
|
|
4
3
|
import { useCatalog } from "../useCatalog";
|
|
@@ -8,10 +7,9 @@ import { buildRequestManifest } from "../useRequestManifest/utils";
|
|
|
8
7
|
/**
|
|
9
8
|
* Returns file manifest download url and file name.
|
|
10
9
|
* @param filters - Filters.
|
|
11
|
-
* @param disabled - Disabled.
|
|
12
10
|
* @returns file manifest download url and file name.
|
|
13
11
|
*/
|
|
14
|
-
export const useFileManifestDownload = (filters
|
|
12
|
+
export const useFileManifestDownload = (filters) => {
|
|
15
13
|
// Retrieve the endpoint URL from configured data source.
|
|
16
14
|
const config = useConfig();
|
|
17
15
|
const endpointUrl = config.config.dataSource.url;
|
|
@@ -19,20 +17,15 @@ export const useFileManifestDownload = (filters, disabled) => {
|
|
|
19
17
|
const catalog = useCatalog(); // catalog should be defined.
|
|
20
18
|
// Build request manifest request URL.
|
|
21
19
|
const { requestMethod, requestUrl } = buildRequestManifest(endpointUrl, catalog, filters, MANIFEST_DOWNLOAD_FORMAT.COMPACT);
|
|
22
|
-
const { data, isIdle, isLoading, run } = useRequestFileLocation(requestUrl, requestMethod);
|
|
20
|
+
const { data, isIdle, isLoading, run: requestManifest, } = useRequestFileLocation(requestUrl, requestMethod);
|
|
23
21
|
const manifestURL = getManifestDownloadURL(data);
|
|
24
22
|
const fileName = getManifestDownloadFileName(data);
|
|
25
|
-
// Requests file manifest.
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
if (disabled)
|
|
28
|
-
return;
|
|
29
|
-
run();
|
|
30
|
-
}, [disabled, requestUrl, run]);
|
|
31
23
|
return {
|
|
32
24
|
fileName,
|
|
33
25
|
isIdle,
|
|
34
26
|
isLoading,
|
|
35
27
|
manifestURL,
|
|
28
|
+
requestManifest,
|
|
36
29
|
};
|
|
37
30
|
};
|
|
38
31
|
/**
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Filters } from "../../common/entities";
|
|
2
2
|
export interface ManifestSpreadsheet {
|
|
3
|
-
exists?: boolean;
|
|
4
|
-
fileFormat?: string;
|
|
5
3
|
fileName?: string;
|
|
6
4
|
fileUrl?: string;
|
|
5
|
+
isIdle?: boolean;
|
|
6
|
+
isLoading?: boolean;
|
|
7
|
+
requestManifest?: () => void;
|
|
8
|
+
spreadsheetUrl?: string;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Returns file manifest spreadsheet.
|
|
10
12
|
* @param filters - Filters.
|
|
11
|
-
* @param disabled - Disabled.
|
|
12
13
|
* @returns file manifest spreadsheet.
|
|
13
14
|
*/
|
|
14
|
-
export declare const useFileManifestSpreadsheet: (filters: Filters
|
|
15
|
+
export declare const useFileManifestSpreadsheet: (filters: Filters) => Omit<ManifestSpreadsheet, "fileUrl">;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { useEffect, useMemo } from "react";
|
|
1
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
2
2
|
import { APIEndpoints, } from "../../apis/azul/common/entities";
|
|
3
3
|
import { fetchEntitiesFromURL } from "../../entity/common/service";
|
|
4
4
|
import { fetchQueryParams } from "../../utils/fetchQueryParams";
|
|
5
5
|
import { useAsync } from "../useAsync";
|
|
6
6
|
import { useCatalog } from "../useCatalog";
|
|
7
7
|
import { useFetchRequestURL } from "../useFetchRequestURL";
|
|
8
|
+
import { useRequestFileLocation } from "../useRequestFileLocation";
|
|
8
9
|
/**
|
|
9
10
|
* Returns file manifest spreadsheet.
|
|
10
11
|
* @param filters - Filters.
|
|
11
|
-
* @param disabled - Disabled.
|
|
12
12
|
* @returns file manifest spreadsheet.
|
|
13
13
|
*/
|
|
14
|
-
export const useFileManifestSpreadsheet = (filters
|
|
14
|
+
export const useFileManifestSpreadsheet = (filters) => {
|
|
15
15
|
// Determine catalog.
|
|
16
16
|
const catalog = useCatalog(); // catalog should be defined.
|
|
17
17
|
// Build request params.
|
|
@@ -19,16 +19,26 @@ export const useFileManifestSpreadsheet = (filters, disabled) => {
|
|
|
19
19
|
// Build request URL.
|
|
20
20
|
const requestURL = useFetchRequestURL(APIEndpoints.FILES, requestParams);
|
|
21
21
|
// Fetch files to determine if file exists.
|
|
22
|
-
const { data, run } = useAsync();
|
|
22
|
+
const { data: files, isIdle, isLoading: isFilesLoading, run: requestFiles, } = useAsync();
|
|
23
23
|
// Grab manifest spreadsheet.
|
|
24
|
-
const
|
|
24
|
+
const { fileName, fileUrl } = useMemo(() => getManifestSpreadsheet(files?.hits), [files]);
|
|
25
|
+
// Fetch file manifest.
|
|
26
|
+
const { data, isLoading, run } = useRequestFileLocation(fileUrl);
|
|
25
27
|
// Fetch response from files endpoint.
|
|
28
|
+
const requestManifest = useCallback(() => {
|
|
29
|
+
requestFiles(fetchEntitiesFromURL(requestURL, undefined));
|
|
30
|
+
}, [requestFiles, requestURL]);
|
|
31
|
+
// Fetch file manifest.
|
|
26
32
|
useEffect(() => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
run();
|
|
34
|
+
}, [fileUrl, run]);
|
|
35
|
+
return {
|
|
36
|
+
fileName,
|
|
37
|
+
isIdle,
|
|
38
|
+
isLoading: isFilesLoading || isLoading,
|
|
39
|
+
requestManifest,
|
|
40
|
+
spreadsheetUrl: data?.location,
|
|
41
|
+
};
|
|
32
42
|
};
|
|
33
43
|
/**
|
|
34
44
|
* Prepend "/fetch" to the path of the specified file URL, if not already included.
|
|
@@ -52,20 +62,14 @@ function buildFetchFileUrl(fileUrl) {
|
|
|
52
62
|
* @returns manifest spreadsheet.
|
|
53
63
|
*/
|
|
54
64
|
function getManifestSpreadsheet(files) {
|
|
55
|
-
if (!files)
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
65
|
+
if (!files)
|
|
66
|
+
return { fileName: undefined, fileUrl: undefined };
|
|
58
67
|
// Handle case where file does not exist.
|
|
59
|
-
if (files.length === 0)
|
|
60
|
-
return {
|
|
61
|
-
exists: false,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
68
|
+
if (files.length === 0)
|
|
69
|
+
return { fileName: undefined, fileUrl: undefined };
|
|
64
70
|
// Project manifest spreadsheet exists.
|
|
65
71
|
const file = files[0];
|
|
66
72
|
return {
|
|
67
|
-
exists: true,
|
|
68
|
-
fileFormat: file.files[0]?.format,
|
|
69
73
|
fileName: file.files[0]?.name,
|
|
70
74
|
fileUrl: buildFetchFileUrl(file.files[0]?.url),
|
|
71
75
|
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ButtonBase,
|
|
3
|
-
TableBody,
|
|
4
|
-
TableCell,
|
|
5
|
-
TableRow,
|
|
6
|
-
Tooltip,
|
|
7
|
-
} from "@mui/material";
|
|
1
|
+
import { Button, TableBody, TableCell, TableRow, Tooltip } from "@mui/material";
|
|
8
2
|
import copy from "copy-to-clipboard";
|
|
9
|
-
import React
|
|
3
|
+
import React from "react";
|
|
10
4
|
import { Filters } from "../../../../../../../../common/entities";
|
|
11
5
|
import { useDownloadStatus } from "../../../../../../../../hooks/useDownloadStatus";
|
|
12
6
|
import { useFileManifestDownload } from "../../../../../../../../hooks/useFileManifest/useFileManifestDownload";
|
|
13
7
|
import { useLoginGuard } from "../../../../../../../../providers/loginGuard/hook";
|
|
8
|
+
import { BUTTON_PROPS } from "../../../../../../../common/Button/constants";
|
|
14
9
|
import { ButtonGroup } from "../../../../../../../common/ButtonGroup/buttonGroup";
|
|
15
|
-
import { ButtonGroupButton } from "../../../../../../../common/ButtonGroup/components/ButtonGroupButton/buttonGroupButton";
|
|
16
10
|
import {
|
|
17
11
|
ContentCopyIconSmall,
|
|
18
12
|
DownloadIconSmall,
|
|
@@ -26,6 +20,7 @@ import {
|
|
|
26
20
|
LOADING_PANEL_STYLE,
|
|
27
21
|
} from "../../../../../../../Loading/loading";
|
|
28
22
|
import { GridTable } from "../../../../../../../Table/common/gridTable.styles";
|
|
23
|
+
import { TOOLTIP_PROPS } from "../../constants";
|
|
29
24
|
import {
|
|
30
25
|
SectionTitle,
|
|
31
26
|
TableContainer,
|
|
@@ -38,87 +33,64 @@ export interface FileManifestDownloadProps {
|
|
|
38
33
|
export const FileManifestDownload = ({
|
|
39
34
|
filters,
|
|
40
35
|
}: FileManifestDownloadProps): JSX.Element => {
|
|
41
|
-
const downloadRef = useRef<HTMLAnchorElement>(null);
|
|
42
36
|
const { disabled, message } = useDownloadStatus();
|
|
43
|
-
const { fileName, isIdle, isLoading, manifestURL } =
|
|
44
|
-
filters
|
|
45
|
-
disabled
|
|
46
|
-
);
|
|
47
|
-
const isInProgress = (isIdle || isLoading) && !disabled;
|
|
48
|
-
const isReady = Boolean(manifestURL) || disabled;
|
|
37
|
+
const { fileName, isIdle, isLoading, manifestURL, requestManifest } =
|
|
38
|
+
useFileManifestDownload(filters);
|
|
49
39
|
|
|
50
40
|
// Prompt user for login before download and copy, if required.
|
|
51
41
|
const { requireLogin } = useLoginGuard();
|
|
52
42
|
|
|
53
|
-
// Copies file manifest.
|
|
54
|
-
const copyManifestURL = (url?: string): void => {
|
|
55
|
-
if (!url) return;
|
|
56
|
-
copy(url);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// Downloads file manifest.
|
|
60
|
-
const downloadManifestURL = (): void => {
|
|
61
|
-
downloadRef.current?.click();
|
|
62
|
-
};
|
|
63
|
-
|
|
64
43
|
return (
|
|
65
44
|
<FluidPaper>
|
|
66
45
|
<GridPaper>
|
|
67
46
|
<SectionTitle>File Manifest</SectionTitle>
|
|
68
47
|
<TableContainer>
|
|
69
48
|
<Loading
|
|
70
|
-
loading={
|
|
49
|
+
loading={isLoading}
|
|
71
50
|
panelStyle={LOADING_PANEL_STYLE.INHERIT}
|
|
72
51
|
/>
|
|
73
|
-
<GridTable gridTemplateColumns=
|
|
52
|
+
<GridTable gridTemplateColumns="auto 1fr">
|
|
74
53
|
<TableBody>
|
|
75
54
|
<TableRow>
|
|
76
|
-
{
|
|
77
|
-
<TableCell
|
|
78
|
-
|
|
55
|
+
{isIdle || isLoading ? (
|
|
56
|
+
<TableCell>
|
|
57
|
+
<Tooltip {...TOOLTIP_PROPS} title={message}>
|
|
58
|
+
<span>
|
|
59
|
+
<Button
|
|
60
|
+
{...BUTTON_PROPS.PRIMARY_CONTAINED}
|
|
61
|
+
disabled={disabled || isLoading}
|
|
62
|
+
onClick={() => requireLogin(requestManifest)}
|
|
63
|
+
>
|
|
64
|
+
Request link
|
|
65
|
+
</Button>
|
|
66
|
+
</span>
|
|
67
|
+
</Tooltip>
|
|
68
|
+
</TableCell>
|
|
69
|
+
) : (
|
|
79
70
|
<>
|
|
71
|
+
{manifestURL && (
|
|
72
|
+
<TableCell>
|
|
73
|
+
<ButtonGroup
|
|
74
|
+
Buttons={[
|
|
75
|
+
<Button key="download" download href={manifestURL}>
|
|
76
|
+
<DownloadIconSmall />
|
|
77
|
+
</Button>,
|
|
78
|
+
<Button
|
|
79
|
+
key="copy"
|
|
80
|
+
onClick={() => copy(manifestURL)}
|
|
81
|
+
>
|
|
82
|
+
<ContentCopyIconSmall />
|
|
83
|
+
</Button>,
|
|
84
|
+
]}
|
|
85
|
+
/>
|
|
86
|
+
</TableCell>
|
|
87
|
+
)}
|
|
80
88
|
<TableCell>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
ref={downloadRef}
|
|
85
|
-
sx={{ display: "none" }}
|
|
86
|
-
/>
|
|
87
|
-
<Tooltip arrow title={message}>
|
|
88
|
-
<span>
|
|
89
|
-
<ButtonGroup
|
|
90
|
-
Buttons={[
|
|
91
|
-
<ButtonGroupButton
|
|
92
|
-
key="download"
|
|
93
|
-
action="Download file manifest"
|
|
94
|
-
disabled={disabled}
|
|
95
|
-
label={<DownloadIconSmall />}
|
|
96
|
-
onClick={() =>
|
|
97
|
-
requireLogin(downloadManifestURL)
|
|
98
|
-
}
|
|
99
|
-
/>,
|
|
100
|
-
<ButtonGroupButton
|
|
101
|
-
key="copy"
|
|
102
|
-
action="Copy file manifest"
|
|
103
|
-
disabled={disabled}
|
|
104
|
-
label={<ContentCopyIconSmall />}
|
|
105
|
-
onClick={() =>
|
|
106
|
-
requireLogin((): void =>
|
|
107
|
-
copyManifestURL(manifestURL)
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
/>,
|
|
111
|
-
]}
|
|
112
|
-
/>
|
|
113
|
-
</span>
|
|
114
|
-
</Tooltip>
|
|
89
|
+
{manifestURL
|
|
90
|
+
? fileName
|
|
91
|
+
: "The manifest is not available for this project."}
|
|
115
92
|
</TableCell>
|
|
116
|
-
<TableCell>{fileName}</TableCell>
|
|
117
93
|
</>
|
|
118
|
-
) : (
|
|
119
|
-
<TableCell>
|
|
120
|
-
The manifest is not available for this project.
|
|
121
|
-
</TableCell>
|
|
122
94
|
)}
|
|
123
95
|
</TableRow>
|
|
124
96
|
</TableBody>
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ButtonBase,
|
|
3
|
-
TableBody,
|
|
4
|
-
TableCell,
|
|
5
|
-
TableRow,
|
|
6
|
-
Tooltip,
|
|
7
|
-
} from "@mui/material";
|
|
1
|
+
import { Button, TableBody, TableCell, TableRow, Tooltip } from "@mui/material";
|
|
8
2
|
import copy from "copy-to-clipboard";
|
|
9
|
-
import React
|
|
3
|
+
import React from "react";
|
|
10
4
|
import { Filters } from "../../../../../../../../common/entities";
|
|
11
5
|
import { useDownloadStatus } from "../../../../../../../../hooks/useDownloadStatus";
|
|
12
6
|
import { useFileManifestSpreadsheet } from "../../../../../../../../hooks/useFileManifest/useFileManifestSpreadsheet";
|
|
13
|
-
import {
|
|
7
|
+
import { BUTTON_PROPS } from "../../../../../../../common/Button/constants";
|
|
14
8
|
import { ButtonGroup } from "../../../../../../../common/ButtonGroup/buttonGroup";
|
|
15
|
-
import { ButtonGroupButton } from "../../../../../../../common/ButtonGroup/components/ButtonGroupButton/buttonGroupButton";
|
|
16
9
|
import {
|
|
17
10
|
ContentCopyIconSmall,
|
|
18
11
|
DownloadIconSmall,
|
|
@@ -26,6 +19,7 @@ import {
|
|
|
26
19
|
LOADING_PANEL_STYLE,
|
|
27
20
|
} from "../../../../../../../Loading/loading";
|
|
28
21
|
import { GridTable } from "../../../../../../../Table/common/gridTable.styles";
|
|
22
|
+
import { TOOLTIP_PROPS } from "../../constants";
|
|
29
23
|
import {
|
|
30
24
|
SectionTitle,
|
|
31
25
|
TableContainer,
|
|
@@ -38,30 +32,14 @@ export interface FileManifestSpreadsheetProps {
|
|
|
38
32
|
export const FileManifestSpreadsheet = ({
|
|
39
33
|
filters,
|
|
40
34
|
}: FileManifestSpreadsheetProps): JSX.Element => {
|
|
41
|
-
const downloadRef = useRef<HTMLAnchorElement>(null);
|
|
42
35
|
const { disabled, message } = useDownloadStatus();
|
|
43
|
-
const {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// Copies metadata spreadsheet.
|
|
51
|
-
const copyMetadataURL = (url?: string): void => {
|
|
52
|
-
if (!url) return;
|
|
53
|
-
copy(url);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// Downloads metadata spreadsheet.
|
|
57
|
-
const downloadMetadataURL = (): void => {
|
|
58
|
-
downloadRef.current?.click();
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// Requests metadata spreadsheet.
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
run();
|
|
64
|
-
}, [fileUrl, run]);
|
|
36
|
+
const {
|
|
37
|
+
fileName,
|
|
38
|
+
isIdle = false,
|
|
39
|
+
isLoading = false,
|
|
40
|
+
requestManifest,
|
|
41
|
+
spreadsheetUrl,
|
|
42
|
+
} = useFileManifestSpreadsheet(filters) || {};
|
|
65
43
|
|
|
66
44
|
return (
|
|
67
45
|
<FluidPaper>
|
|
@@ -69,55 +47,55 @@ export const FileManifestSpreadsheet = ({
|
|
|
69
47
|
<SectionTitle>Metadata</SectionTitle>
|
|
70
48
|
<TableContainer>
|
|
71
49
|
<Loading
|
|
72
|
-
loading={
|
|
50
|
+
loading={isLoading}
|
|
73
51
|
panelStyle={LOADING_PANEL_STYLE.INHERIT}
|
|
74
52
|
/>
|
|
75
|
-
<GridTable gridTemplateColumns=
|
|
53
|
+
<GridTable gridTemplateColumns="auto 1fr">
|
|
76
54
|
<TableBody>
|
|
77
55
|
<TableRow>
|
|
78
|
-
{
|
|
79
|
-
<TableCell
|
|
80
|
-
|
|
56
|
+
{isIdle || isLoading ? (
|
|
57
|
+
<TableCell>
|
|
58
|
+
<Tooltip {...TOOLTIP_PROPS} title={message}>
|
|
59
|
+
<span>
|
|
60
|
+
<Button
|
|
61
|
+
{...BUTTON_PROPS.PRIMARY_CONTAINED}
|
|
62
|
+
disabled={disabled || isLoading}
|
|
63
|
+
onClick={() => requestManifest?.()}
|
|
64
|
+
>
|
|
65
|
+
Request link
|
|
66
|
+
</Button>
|
|
67
|
+
</span>
|
|
68
|
+
</Tooltip>
|
|
69
|
+
</TableCell>
|
|
70
|
+
) : (
|
|
81
71
|
<>
|
|
72
|
+
{spreadsheetUrl && (
|
|
73
|
+
<TableCell>
|
|
74
|
+
<ButtonGroup
|
|
75
|
+
Buttons={[
|
|
76
|
+
<Button
|
|
77
|
+
key="download"
|
|
78
|
+
download
|
|
79
|
+
href={spreadsheetUrl}
|
|
80
|
+
>
|
|
81
|
+
<DownloadIconSmall />
|
|
82
|
+
</Button>,
|
|
83
|
+
<Button
|
|
84
|
+
key="copy"
|
|
85
|
+
onClick={() => copy(spreadsheetUrl)}
|
|
86
|
+
>
|
|
87
|
+
<ContentCopyIconSmall />
|
|
88
|
+
</Button>,
|
|
89
|
+
]}
|
|
90
|
+
/>
|
|
91
|
+
</TableCell>
|
|
92
|
+
)}
|
|
82
93
|
<TableCell>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
href={spreadsheetURL ?? ""}
|
|
87
|
-
ref={downloadRef}
|
|
88
|
-
sx={{ display: "none" }}
|
|
89
|
-
/>
|
|
90
|
-
<Tooltip arrow title={message}>
|
|
91
|
-
<span>
|
|
92
|
-
<ButtonGroup
|
|
93
|
-
Buttons={[
|
|
94
|
-
<ButtonGroupButton
|
|
95
|
-
key="download"
|
|
96
|
-
action="Download metadata spreadsheet"
|
|
97
|
-
disabled={disabled}
|
|
98
|
-
label={<DownloadIconSmall />}
|
|
99
|
-
onClick={downloadMetadataURL}
|
|
100
|
-
/>,
|
|
101
|
-
<ButtonGroupButton
|
|
102
|
-
key="copy"
|
|
103
|
-
action="Copy metadata spreadsheet"
|
|
104
|
-
disabled={disabled}
|
|
105
|
-
label={<ContentCopyIconSmall />}
|
|
106
|
-
onClick={(): void =>
|
|
107
|
-
copyMetadataURL(spreadsheetURL)
|
|
108
|
-
}
|
|
109
|
-
/>,
|
|
110
|
-
]}
|
|
111
|
-
/>
|
|
112
|
-
</span>
|
|
113
|
-
</Tooltip>
|
|
94
|
+
{spreadsheetUrl
|
|
95
|
+
? fileName
|
|
96
|
+
: "The metadata is not available for this project."}
|
|
114
97
|
</TableCell>
|
|
115
|
-
<TableCell>{fileName}</TableCell>
|
|
116
98
|
</>
|
|
117
|
-
) : (
|
|
118
|
-
<TableCell>
|
|
119
|
-
The metadata is not available for this project.
|
|
120
|
-
</TableCell>
|
|
121
99
|
)}
|
|
122
100
|
</TableRow>
|
|
123
101
|
</TableBody>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TooltipProps } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
export const TOOLTIP_PROPS: Partial<TooltipProps> = {
|
|
4
|
+
arrow: true,
|
|
5
|
+
slotProps: {
|
|
6
|
+
popper: {
|
|
7
|
+
modifiers: [
|
|
8
|
+
{
|
|
9
|
+
name: "offset",
|
|
10
|
+
options: {
|
|
11
|
+
offset: [0, -4],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "preventOverflow",
|
|
16
|
+
options: { padding: 8 },
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
tooltip: {
|
|
21
|
+
sx: { maxWidth: "none" },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
import { Chip } from "@mui/material";
|
|
3
|
+
import { PALETTE } from "../../../../../../styles/common/constants/palette";
|
|
4
|
+
|
|
5
|
+
export const StyledChip = styled(Chip)`
|
|
6
|
+
border-radius: 4px;
|
|
7
|
+
box-shadow: 0 0 0 2px ${PALETTE.COMMON_WHITE};
|
|
8
|
+
height: auto;
|
|
9
|
+
justify-self: flex-start;
|
|
10
|
+
min-width: 0;
|
|
11
|
+
|
|
12
|
+
.MuiChip-label {
|
|
13
|
+
padding: 2px 8px;
|
|
14
|
+
white-space: normal;
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CellContext, RowData } from "@tanstack/react-table";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { CHIP_PROPS } from "../../../../../../styles/common/mui/chip";
|
|
4
|
+
import { BaseComponentProps } from "../../../../../types";
|
|
5
|
+
import { StyledChip } from "./codeCell.styles";
|
|
6
|
+
|
|
7
|
+
export const CodeCell = <T extends RowData, TValue extends string = string>({
|
|
8
|
+
className,
|
|
9
|
+
getValue,
|
|
10
|
+
}: BaseComponentProps & CellContext<T, TValue>): JSX.Element | null => {
|
|
11
|
+
const value = getValue();
|
|
12
|
+
if (!value) return null;
|
|
13
|
+
return (
|
|
14
|
+
<StyledChip
|
|
15
|
+
className={className}
|
|
16
|
+
color={CHIP_PROPS.COLOR.DEFAULT}
|
|
17
|
+
label={value}
|
|
18
|
+
size={CHIP_PROPS.SIZE.SMALL}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
1
|
import { MANIFEST_DOWNLOAD_FORMAT } from "../../apis/azul/common/entities";
|
|
3
2
|
import { Filters } from "../../common/entities";
|
|
4
3
|
import { BULK_DOWNLOAD_EXECUTION_ENVIRONMENT } from "../../components/Export/common/entities";
|
|
@@ -15,18 +14,15 @@ export interface ManifestDownload {
|
|
|
15
14
|
isIdle: boolean;
|
|
16
15
|
isLoading: boolean;
|
|
17
16
|
manifestURL?: string;
|
|
17
|
+
requestManifest: () => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Returns file manifest download url and file name.
|
|
22
22
|
* @param filters - Filters.
|
|
23
|
-
* @param disabled - Disabled.
|
|
24
23
|
* @returns file manifest download url and file name.
|
|
25
24
|
*/
|
|
26
|
-
export const useFileManifestDownload = (
|
|
27
|
-
filters: Filters,
|
|
28
|
-
disabled: boolean
|
|
29
|
-
): ManifestDownload => {
|
|
25
|
+
export const useFileManifestDownload = (filters: Filters): ManifestDownload => {
|
|
30
26
|
// Retrieve the endpoint URL from configured data source.
|
|
31
27
|
const config = useConfig();
|
|
32
28
|
const endpointUrl = config.config.dataSource.url;
|
|
@@ -39,24 +35,21 @@ export const useFileManifestDownload = (
|
|
|
39
35
|
filters,
|
|
40
36
|
MANIFEST_DOWNLOAD_FORMAT.COMPACT
|
|
41
37
|
);
|
|
42
|
-
const {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
const {
|
|
39
|
+
data,
|
|
40
|
+
isIdle,
|
|
41
|
+
isLoading,
|
|
42
|
+
run: requestManifest,
|
|
43
|
+
} = useRequestFileLocation(requestUrl, requestMethod);
|
|
46
44
|
const manifestURL = getManifestDownloadURL(data);
|
|
47
45
|
const fileName = getManifestDownloadFileName(data);
|
|
48
46
|
|
|
49
|
-
// Requests file manifest.
|
|
50
|
-
useEffect(() => {
|
|
51
|
-
if (disabled) return;
|
|
52
|
-
run();
|
|
53
|
-
}, [disabled, requestUrl, run]);
|
|
54
|
-
|
|
55
47
|
return {
|
|
56
48
|
fileName,
|
|
57
49
|
isIdle,
|
|
58
50
|
isLoading,
|
|
59
51
|
manifestURL,
|
|
52
|
+
requestManifest,
|
|
60
53
|
};
|
|
61
54
|
};
|
|
62
55
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useMemo } from "react";
|
|
1
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
2
2
|
import {
|
|
3
3
|
APIEndpoints,
|
|
4
4
|
AzulEntitiesResponse,
|
|
@@ -9,24 +9,25 @@ import { fetchQueryParams } from "../../utils/fetchQueryParams";
|
|
|
9
9
|
import { useAsync } from "../useAsync";
|
|
10
10
|
import { useCatalog } from "../useCatalog";
|
|
11
11
|
import { useFetchRequestURL } from "../useFetchRequestURL";
|
|
12
|
+
import { useRequestFileLocation } from "../useRequestFileLocation";
|
|
12
13
|
|
|
13
14
|
export interface ManifestSpreadsheet {
|
|
14
|
-
exists?: boolean;
|
|
15
|
-
fileFormat?: string;
|
|
16
15
|
fileName?: string;
|
|
17
16
|
fileUrl?: string;
|
|
17
|
+
isIdle?: boolean;
|
|
18
|
+
isLoading?: boolean;
|
|
19
|
+
requestManifest?: () => void;
|
|
20
|
+
spreadsheetUrl?: string;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Returns file manifest spreadsheet.
|
|
22
25
|
* @param filters - Filters.
|
|
23
|
-
* @param disabled - Disabled.
|
|
24
26
|
* @returns file manifest spreadsheet.
|
|
25
27
|
*/
|
|
26
28
|
export const useFileManifestSpreadsheet = (
|
|
27
|
-
filters: Filters
|
|
28
|
-
|
|
29
|
-
): ManifestSpreadsheet | undefined => {
|
|
29
|
+
filters: Filters
|
|
30
|
+
): Omit<ManifestSpreadsheet, "fileUrl"> => {
|
|
30
31
|
// Determine catalog.
|
|
31
32
|
const catalog = useCatalog() as string; // catalog should be defined.
|
|
32
33
|
// Build request params.
|
|
@@ -34,20 +35,39 @@ export const useFileManifestSpreadsheet = (
|
|
|
34
35
|
// Build request URL.
|
|
35
36
|
const requestURL = useFetchRequestURL(APIEndpoints.FILES, requestParams);
|
|
36
37
|
// Fetch files to determine if file exists.
|
|
37
|
-
const {
|
|
38
|
+
const {
|
|
39
|
+
data: files,
|
|
40
|
+
isIdle,
|
|
41
|
+
isLoading: isFilesLoading,
|
|
42
|
+
run: requestFiles,
|
|
43
|
+
} = useAsync<AzulEntitiesResponse>();
|
|
44
|
+
|
|
38
45
|
// Grab manifest spreadsheet.
|
|
39
|
-
const
|
|
40
|
-
() => getManifestSpreadsheet(
|
|
41
|
-
[
|
|
46
|
+
const { fileName, fileUrl } = useMemo(
|
|
47
|
+
() => getManifestSpreadsheet(files?.hits),
|
|
48
|
+
[files]
|
|
42
49
|
);
|
|
43
50
|
|
|
51
|
+
// Fetch file manifest.
|
|
52
|
+
const { data, isLoading, run } = useRequestFileLocation(fileUrl);
|
|
53
|
+
|
|
44
54
|
// Fetch response from files endpoint.
|
|
55
|
+
const requestManifest = useCallback(() => {
|
|
56
|
+
requestFiles(fetchEntitiesFromURL(requestURL, undefined));
|
|
57
|
+
}, [requestFiles, requestURL]);
|
|
58
|
+
|
|
59
|
+
// Fetch file manifest.
|
|
45
60
|
useEffect(() => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}, [disabled, requestURL, run]);
|
|
61
|
+
run();
|
|
62
|
+
}, [fileUrl, run]);
|
|
49
63
|
|
|
50
|
-
return
|
|
64
|
+
return {
|
|
65
|
+
fileName,
|
|
66
|
+
isIdle,
|
|
67
|
+
isLoading: isFilesLoading || isLoading,
|
|
68
|
+
requestManifest,
|
|
69
|
+
spreadsheetUrl: data?.location,
|
|
70
|
+
};
|
|
51
71
|
};
|
|
52
72
|
|
|
53
73
|
/**
|
|
@@ -74,21 +94,16 @@ function buildFetchFileUrl(fileUrl?: string): string | undefined {
|
|
|
74
94
|
*/
|
|
75
95
|
function getManifestSpreadsheet(
|
|
76
96
|
files?: AzulEntitiesResponse["hits"]
|
|
77
|
-
): ManifestSpreadsheet |
|
|
78
|
-
if (!files) {
|
|
79
|
-
|
|
80
|
-
}
|
|
97
|
+
): Pick<ManifestSpreadsheet, "fileName" | "fileUrl"> {
|
|
98
|
+
if (!files) return { fileName: undefined, fileUrl: undefined };
|
|
99
|
+
|
|
81
100
|
// Handle case where file does not exist.
|
|
82
|
-
if (files.length === 0) {
|
|
83
|
-
|
|
84
|
-
exists: false,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
101
|
+
if (files.length === 0) return { fileName: undefined, fileUrl: undefined };
|
|
102
|
+
|
|
87
103
|
// Project manifest spreadsheet exists.
|
|
88
104
|
const file = files[0];
|
|
105
|
+
|
|
89
106
|
return {
|
|
90
|
-
exists: true,
|
|
91
|
-
fileFormat: file.files[0]?.format,
|
|
92
107
|
fileName: file.files[0]?.name,
|
|
93
108
|
fileUrl: buildFetchFileUrl(file.files[0]?.url),
|
|
94
109
|
};
|