Skip to content

Commit

Permalink
Add ability to set a URL for the file download (#2340)
Browse files Browse the repository at this point in the history
This change originally comes from #2151. It is added here in a separate
PR to make it easier to continue working on the file select components
while #2151 is still in the works.
  • Loading branch information
jamesricky authored Jul 25, 2024
1 parent 53f5439 commit 1aee56c
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 22 deletions.
39 changes: 23 additions & 16 deletions packages/admin/admin/src/form/file/FileSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Alert } from "../../alert/Alert";
import { createComponentSlot } from "../../helpers/createComponentSlot";
import { ThemedComponentBaseProps } from "../../helpers/ThemedComponentBaseProps";
import { FileDropzone } from "./FileDropzone";
import { FileSelectItem } from "./fileSelectItemTypes";
import { FileSelectItem, ValidFileSelectItem } from "./fileSelectItemTypes";
import { FileSelectListItem } from "./FileSelectListItem";
import { getFilesInfoText } from "./getFilesInfoText";

Expand Down Expand Up @@ -39,6 +39,7 @@ export type FileSelectProps<AdditionalValidFileValues = Record<string, unknown>>
onDrop?: DropzoneOptions["onDrop"];
onRemove?: (file: FileSelectItem<AdditionalValidFileValues>) => void;
onDownload?: (file: FileSelectItem<AdditionalValidFileValues>) => void;
getDownloadUrl?: (file: ValidFileSelectItem<AdditionalValidFileValues>) => string;
disabled?: boolean;
readOnly?: boolean;
accept?: Accept;
Expand All @@ -64,6 +65,7 @@ export const FileSelect = <AdditionalValidFileValues = Record<string, unknown>,>
onDrop,
onRemove,
onDownload,
getDownloadUrl,
files,
error,
...restProps
Expand Down Expand Up @@ -117,21 +119,26 @@ export const FileSelect = <AdditionalValidFileValues = Record<string, unknown>,>
<FileList {...slotProps?.fileList}>
{files.length > 0 ? (
<>
{files.map((file, index) => (
<FileListItem
key={index}
file={file}
onClickDownload={
"error" in file || !onDownload
? undefined
: () => {
onDownload(file);
}
}
onClickDelete={readOnly || !onRemove ? undefined : () => onRemove(file)}
{...slotProps?.fileListItem}
/>
))}
{files.map((file, index) => {
const isValidFile = !("error" in file) && !("loading" in file);

return (
<FileListItem
key={index}
file={file}
onClickDownload={
isValidFile && onDownload
? () => {
onDownload(file);
}
: undefined
}
downloadUrl={isValidFile && getDownloadUrl ? getDownloadUrl(file) : undefined}
onClickDelete={readOnly || !onRemove ? undefined : () => onRemove(file)}
{...slotProps?.fileListItem}
/>
);
})}
</>
) : (
<FileListItem
Expand Down
10 changes: 8 additions & 2 deletions packages/admin/admin/src/form/file/FileSelectListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type FileSelectListItemProps = ThemedComponentBaseProps<{
file: FileSelectItem;
disabled?: boolean;
onClickDownload?: () => void;
downloadUrl?: string;
onClickDelete?: () => void;
iconMapping?: {
download?: React.ReactNode;
Expand All @@ -68,6 +69,7 @@ export const FileSelectListItem = (inProps: FileSelectListItemProps) => {
file,
disabled,
onClickDownload,
downloadUrl,
onClickDelete,
iconMapping = {},
slotProps,
Expand Down Expand Up @@ -115,8 +117,12 @@ export const FileSelectListItem = (inProps: FileSelectListItemProps) => {
{ownerState.hasErrorWithoutDetails && (
<ErrorIconContainer {...slotProps?.errorIconContainer}>{errorIcon}</ErrorIconContainer>
)}
{Boolean(onClickDownload) && (
<IconButton onClick={onClickDownload} disabled={disabled} {...slotProps?.iconButton}>
{(Boolean(onClickDownload) || !!downloadUrl) && (
<IconButton
disabled={disabled}
{...(downloadUrl ? { href: downloadUrl, download: true } : { onClick: onClickDownload })}
{...slotProps?.iconButton}
>
{downloadIcon}
</IconButton>
)}
Expand Down
7 changes: 5 additions & 2 deletions storybook/src/admin/form/file/FileSelectListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ storiesOf("@comet/admin/form/File", module)
Skeleton: { loading: true },
};

const downloadMethods = ["No download", "Download function", "Download URL"];

const selectedFile = select("File Item", fileItems, fileItems["Valid File"]);
const canBeDownloaded = boolean("Can Be Downloaded", true);
const downloadMethod = select("Can be downloaded", downloadMethods, downloadMethods[0]);
const canBeDeleted = boolean("Can Be Deleted", true);
const disabled = boolean("Disabled", false);

return (
<FileSelectListItem
file={selectedFile}
onClickDownload={canBeDownloaded ? () => alert("Download") : undefined}
onClickDownload={downloadMethod === "Download function" ? () => alert("Downloading file") : undefined}
downloadUrl={downloadMethod === "Download URL" ? "https://example.com" : undefined}
onClickDelete={canBeDeleted ? () => alert("Delete") : undefined}
disabled={disabled}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Used to combine `FileDropzone` and `FileSelectListItem` to handle the user's sel

- Use props from [react-dropzone](https://www.npmjs.com/package/react-dropzone), such as `onDrop`, to handle what happens when selecting files.
- Use the `files` prop to pass in the list of files that should be shown.
- Use the `onDownload` and `onRemove` props to handle what happens when clicking the download and remove buttons.
- Use the `getDownloadUrl`, `onDownload` and `onRemove` props to handle what happens when clicking the download and remove buttons.
- Limit the amount of files and the size of the individual files with the `maxFiles` and `maxFileSize` props.

<Canvas>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Used to display a list of files, including loading, skeleton, and error states a
- If the `loading` value is `true` and `name` is provided, the file will be rendered in a loading state.
- If the `loading` value is `true` and no `name` is provided, the file will be rendered as a skeleton.
- The file will be rendered in an error state if the `error` value is `true` or a string with an error message is provided.
- Use the `onDownload` and `onDelete` props to handle what happens when clicking the download and delete buttons.
- Use the `downloadUrl`, `onClickDownload` and `onClickDelete` props to handle what happens when clicking the download and delete buttons.

<Canvas>
<Story id="stories-components-fileselectlistitem--fileselectlistitem" />
Expand Down

0 comments on commit 1aee56c

Please sign in to comment.