Skip to content

Commit

Permalink
feat(app-file-manager): add file thumbnail and action config
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavel910 committed Apr 25, 2024
1 parent cafef9a commit 412cfd6
Show file tree
Hide file tree
Showing 44 changed files with 503 additions and 362 deletions.
1 change: 0 additions & 1 deletion packages/app-file-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"emotion": "^10.0.17",
"graphql": "^15.7.2",
"graphql-tag": "^2.12.6",
"invariant": "^2.2.4",
"lodash": "4.17.21",
"mime": "^2.4.2",
"minimatch": "^5.1.0",
Expand Down
39 changes: 0 additions & 39 deletions packages/app-file-manager/src/FileManagerFileTypePlugin.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/app-file-manager/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import { SettingsModule } from "~/modules/Settings";
import { FileManagerApiProviderModule } from "~/modules/FileManagerApiProvider";
import { FileTypesModule } from "~/modules/FileTypes";
import { FileManagerRendererModule } from "~/modules/FileManagerRenderer";
import { HeadlessCmsModule } from "~/modules/HeadlessCms";

Expand All @@ -10,7 +9,6 @@ export const FileManager = () => {
<>
<SettingsModule />
<FileManagerApiProviderModule />
<FileTypesModule />
<FileManagerRendererModule />
<HeadlessCmsModule />
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const FileDetailsInner = ({ file, actions, ...props }: FileDetailsInnerProps) =>
<Content>
<Content.Panel flex={parseFloat(leftPanel)}>
<Elevation z={2} style={{ margin: 20 }}>
<Actions file={file} actions={actions} />
<Actions actions={actions} />
<Preview />
<PreviewMeta />
</Elevation>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import { Tooltip } from "@webiny/ui/Tooltip";
import { IconButton } from "@webiny/ui/Button";

export interface ActionButtonProps {
label: string;
icon: JSX.Element;
onAction: () => void;
"data-testid"?: string;
disabled?: boolean;
}

export const ActionButton = ({ label, icon, onAction, disabled, ...props }: ActionButtonProps) => {
return (
<Tooltip content={<span>{label}</span>} placement={"bottom"}>
<IconButton
icon={icon}
onClick={onAction}
disabled={disabled}
data-testid={props["data-testid"]}
/>
</Tooltip>
);
};
Original file line number Diff line number Diff line change
@@ -1,53 +1,20 @@
import React from "react";
import get from "lodash/get";
import React, { Fragment } from "react";
import styled from "@emotion/styled";
import { FileItem } from "@webiny/app-admin/types";
import getFileTypePlugin from "~/getFileTypePlugin";
import { CopyUrl } from "./actions/CopyUrl";
import { DeleteImage } from "./actions/DeleteImage";
import { Download } from "./actions/Download";
import { MoveTo } from "./actions/MoveTo";
import { useFileManagerViewConfig } from "~/index";

const ActionsContainer = styled.div`
text-align: center;
border-bottom: 1px solid var(--mdc-theme-on-background);
`;

interface CustomActionProps {
file: FileItem;
}

interface ActionsProps {
file: FileItem;
actions: FileDetailsActions;
}

export interface FileDetailsActions {
copyUrl: boolean;
delete: boolean;
download: boolean;
edit: boolean;
moveToFolder: boolean;
}

export const Actions = ({ file, actions }: ActionsProps) => {
const filePlugin = getFileTypePlugin(file);

// TODO: implement actions using component composition
const customActions: React.ComponentType<CustomActionProps>[] =
get(filePlugin, "fileDetails.actions") || get(filePlugin, "actions") || [];
export const Actions = () => {
const { fileDetails } = useFileManagerViewConfig();

return (
<ActionsContainer>
{actions.download ? <Download /> : null}
{actions.moveToFolder ? <MoveTo /> : null}
{actions.copyUrl ? <CopyUrl /> : null}
{customActions.map(
(Component: React.ComponentType<CustomActionProps>, index: number) => (
<Component key={index} file={file} />
)
)}
{actions.delete ? <DeleteImage /> : null}
{fileDetails.actions.map(action => (
<Fragment key={action.name}>{action.element}</Fragment>
))}
</ActionsContainer>
);
};
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import React from "react";
import getFileTypePlugin from "~/getFileTypePlugin";
import { useFile } from "~/hooks/useFile";
import { useFileManagerViewConfig } from "~/modules/FileManagerRenderer/FileManagerView/FileManagerViewConfig";

/**
* This component is used in the file grid to render thumbnails, as well as in the File Details preview.
*/
export const Thumbnail = () => {
const { file } = useFile();
const filePlugin = getFileTypePlugin(file);
const { fileDetails, getThumbnailRenderer } = useFileManagerViewConfig();

// TODO: implement preview rendering using component composition
const renderer = getThumbnailRenderer(fileDetails.thumbnails, file);

return filePlugin ? (
<>{filePlugin.render({ file, width: 600 })}</>
) : (
<span>No Preview Available.</span>
);
return <>{renderer?.element || null}</>;
};

This file was deleted.

This file was deleted.

This file was deleted.

20 changes: 20 additions & 0 deletions packages/app-file-manager/src/components/Grid/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import { IconButton } from "@webiny/ui/Button";

export interface ActionButtonProps {
icon: JSX.Element;
onAction: () => void;
"data-testid"?: string;
disabled?: boolean;
}

export const ActionButton = ({ icon, onAction, disabled, ...props }: ActionButtonProps) => {
return (
<IconButton
icon={icon}
onClick={onAction}
disabled={disabled}
data-testid={props["data-testid"]}
/>
);
};
36 changes: 9 additions & 27 deletions packages/app-file-manager/src/components/Grid/File.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import React, { useCallback } from "react";
import React, { Fragment } from "react";
/**
* Package react-lazy-load has no types.
*/
// @ts-expect-error
import LazyLoad from "react-lazy-load";
import { TimeAgo } from "@webiny/ui/TimeAgo";
import { IconButton } from "@webiny/ui/Button";
import { Typography } from "@webiny/ui/Typography";
import { ReactComponent as SettingsIcon } from "@material-design-icons/svg/filled/settings.svg";
import { ReactComponent as DownloadIcon } from "@material-design-icons/svg/filled/download.svg";
import { ReactComponent as MoveIcon } from "@material-design-icons/svg/filled/drive_file_move.svg";

import { ReactComponent as SelectedMarker } from "@material-design-icons/svg/filled/check_circle.svg";

import { FileItem } from "@webiny/app-admin/types";
Expand All @@ -24,7 +21,7 @@ import {
FilePreview,
FileWrapper
} from "./styled";
import { useMoveFileToFolder } from "~/hooks/useMoveFileToFolder";
import { useFileManagerViewConfig } from "~/modules/FileManagerRenderer/FileManagerView/FileManagerViewConfig";

export interface FileOptions {
label: string;
Expand All @@ -39,36 +36,21 @@ export interface FileProps {
options?: FileOptions[];
multiple?: boolean;
children: React.ReactNode;
showFileDetails: (id: string) => void;
}

export const FileThumbnail = ({
file,
selected,
onSelect,
children,
showFileDetails
}: FileProps) => {
const showDetails = useCallback(() => {
showFileDetails(file.id);
}, [file.id]);
export const FileThumbnail = ({ file, selected, onSelect, children }: FileProps) => {
const { browser } = useFileManagerViewConfig();

const moveToFolder = useMoveFileToFolder(file);
const { itemActions } = browser.grid;

return (
<FileWrapper data-testid={"fm-list-wrapper-file"}>
<FileBody>
<FileControls>
<FileInfoIcon>
<a rel="noreferrer" target={"_blank"} href={`${file.src}?original`}>
<IconButton icon={<DownloadIcon />} />
</a>
<IconButton icon={<MoveIcon />} onClick={moveToFolder} />
<IconButton
icon={<SettingsIcon />}
onClick={showDetails}
data-testid={"fm-file-wrapper-file-info-icon"}
/>
{itemActions.map(action => {
return <Fragment key={action.name}>{action.element}</Fragment>;
})}
</FileInfoIcon>
{onSelect ? (
<FileSelectedMarker
Expand Down
5 changes: 1 addition & 4 deletions packages/app-file-manager/src/components/Grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { FileThumbnail } from "./File";
import { FileList, FolderList } from "./styled";
import { FolderItem } from "@webiny/app-aco/types";
import { FileItem } from "@webiny/app-admin/types";
import { Thumbnail } from "~/components/FileDetails/components/Thumbnail";
import { Thumbnail } from "./Thumbnail";
import { FileProvider } from "~/contexts/FileProvider";

const t = i18n.ns("app-admin/file-manager/components/grid");
Expand All @@ -15,7 +15,6 @@ interface GridProps {
records: FileItem[];
folders: FolderItem[];
loading?: boolean;
onRecordClick: (id: string) => void;
onFolderClick: (id: string) => void;
selected: FileItem[];
multiple?: boolean;
Expand All @@ -30,7 +29,6 @@ export const Grid = ({
folders,
records,
loading,
onRecordClick,
onFolderClick,
selected,
onChange,
Expand Down Expand Up @@ -75,7 +73,6 @@ export const Grid = ({
<FileThumbnail
file={record}
multiple={Boolean(multiple)}
showFileDetails={onRecordClick}
selected={selected.some(current => current.id === record.id)}
onSelect={onSelect ? onSelect(record) : undefined}
>
Expand Down
15 changes: 15 additions & 0 deletions packages/app-file-manager/src/components/Grid/Thumbnail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import { useFile } from "~/hooks/useFile";
import { useFileManagerViewConfig } from "~/modules/FileManagerRenderer/FileManagerView/FileManagerViewConfig";

/**
* This component is used in the file grid to render thumbnails, as well as in the File Details preview.
*/
export const Thumbnail = () => {
const { file } = useFile();
const { browser, getThumbnailRenderer } = useFileManagerViewConfig();

const renderer = getThumbnailRenderer(browser.grid.itemThumbnails, file);

return <>{renderer?.element || null}</>;
};
Loading

0 comments on commit 412cfd6

Please sign in to comment.