Web: Files: Added SelectFileDialog component.

This commit is contained in:
Tatiana Lopaeva 2021-07-01 15:31:41 +03:00
parent ee35648212
commit 568aeb86af
5 changed files with 721 additions and 0 deletions

View File

@ -0,0 +1,91 @@
import React from "react";
import {
StyledAsidePanel,
StyledSelectFilePanel,
StyledHeaderContent,
} from "../StyledPanels";
import Text from "@appserver/components/text";
import SelectFolderInput from "../SelectFolderInput";
import FilesListBody from "./fileListBody";
import Aside from "@appserver/components/aside";
import Heading from "@appserver/components/heading";
import Backdrop from "@appserver/components/backdrop";
const DISPLAY_TYPE = "aside";
const SelectFileDialogAsideView = ({
t,
isPanelVisible,
zIndex,
onClose,
isVisible,
isCommonWithoutProvider,
foldersType,
isLoadingData,
onSelectFile,
onClickInput,
onCloseSelectFolderDialog,
onSelectFolder,
onSetLoadingData,
filesList,
hasNextPage,
isNextPageLoading,
loadNextPage,
selectedFolder,
iconUrl,
}) => {
console.log("isLoadingData", isLoadingData, "selectedFolder", selectedFolder);
return (
<StyledAsidePanel visible={isPanelVisible}>
<Backdrop
onClick={onClose}
visible={isPanelVisible}
zIndex={zIndex}
isAside={true}
/>
<Aside visible={isPanelVisible} zIndex={zIndex}>
<StyledSelectFilePanel displayType={DISPLAY_TYPE}>
<StyledHeaderContent className="select-file-dialog_aside-header">
<Heading
size="medium"
className="select-file-dialog_aside-header_title"
>
{t("SelectFile")}
</Heading>
</StyledHeaderContent>
<div className="select-file-dialog_aside-body_wrapper">
<Text fontWeight="600" fontSize="14px">
{t("ChooseFolderByUser")}
</Text>
<div className="select-file-dialog_aside_body">
<SelectFolderInput
onClickInput={onClickInput}
onClose={onCloseSelectFolderDialog}
onSelectFolder={onSelectFolder}
onSetLoadingData={onSetLoadingData}
isPanelVisible={isVisible}
foldersType={foldersType}
isNeedArrowIcon
isCommonWithoutProvider={isCommonWithoutProvider}
/>
{selectedFolder && (
<FilesListBody
isLoadingData={isLoadingData}
filesList={filesList}
onSelectFile={onSelectFile}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={loadNextPage}
selectedFolder={selectedFolder}
displayType={DISPLAY_TYPE}
iconUrl={iconUrl}
/>
)}
</div>
</div>
</StyledSelectFilePanel>
</Aside>
</StyledAsidePanel>
);
};
export default SelectFileDialogAsideView;

View File

@ -0,0 +1,151 @@
import React, { useCallback } from "react";
import Loader from "@appserver/components/loader";
import Text from "@appserver/components/text";
import { useTranslation, withTranslation } from "react-i18next";
import CustomScrollbarsVirtualList from "@appserver/components/scrollbar/custom-scrollbars-virtual-list";
import InfiniteLoader from "react-window-infinite-loader";
import AutoSizer from "react-virtualized-auto-sizer";
import { FixedSizeList as List } from "react-window";
import { inject, observer } from "mobx-react";
import ListRow from "./listRow";
const FilesListBody = ({
filesList,
onSelectFile,
loadNextPage,
hasNextPage,
isNextPageLoading,
displayType,
viewer,
listHeight,
needRowSelection,
emptyFilesList,
loadingLabel,
iconUrl,
}) => {
const { t } = useTranslation(["SelectFile", "Common"]);
// Every row is loaded except for our loading indicator row.
const isItemLoaded = useCallback(
(index) => {
return !hasNextPage || index < filesList.length;
},
[hasNextPage, filesList]
);
// If there are more items to be loaded then add an extra row to hold a loading indicator.
const itemCount = hasNextPage ? filesList.length + 1 : filesList.length;
const loadMoreItems = useCallback(
(startIndex) => {
if (isNextPageLoading) return;
console.log("startIndex", startIndex);
const options = {
startIndex: startIndex || 0,
};
loadNextPage && loadNextPage(options);
},
[isNextPageLoading, filesList]
);
const renderLoader = useCallback(
(style) => {
return (
<div style={style} className="row-option">
<div key="loader">
<Loader
type="oval"
size="16px"
style={{
display: "inline",
marginRight: "10px",
}}
/>
<Text as="span">{"Hello"}</Text>
</div>
</div>
);
},
[loadingLabel]
);
const Item = useCallback(
({ index, style }) => {
const isLoaded = isItemLoaded(index);
if (!isLoaded) {
return renderLoader(style);
}
const file = filesList[index];
const fileName = file.title;
const fileExst = file.fileExst;
const modifyFileName = fileName.substring(
0,
fileName.indexOf(`${fileExst}`)
);
const fileOwner =
file.createdBy &&
((viewer.id === file.createdBy.id && t("Common:MeLabel")) ||
file.createdBy.displayName);
return (
<div style={style}>
<ListRow
displayType={displayType}
needRowSelection={needRowSelection}
index={index}
onSelectFile={onSelectFile}
fileName={modifyFileName}
fileExst={fileExst}
iconUrl={iconUrl}
>
<Text data-index={index} className="files-list_file-owner">
{fileOwner}
</Text>
</ListRow>
</div>
);
},
[filesList, renderLoader]
);
return (
<>
<AutoSizer>
{({ width, height }) => (
<InfiniteLoader
//ref={listOptionsRef}
isItemLoaded={isItemLoaded}
itemCount={itemCount}
loadMoreItems={loadMoreItems}
>
{({ onItemsRendered, ref }) => (
<List
className="options_list"
height={displayType === "aside" ? height : listHeight}
itemCount={itemCount}
itemSize={displayType === "aside" ? 56 : 36}
onItemsRendered={onItemsRendered}
ref={ref}
width={width + 8}
outerElementType={CustomScrollbarsVirtualList}
>
{Item}
</List>
)}
</InfiniteLoader>
)}
</AutoSizer>
{!hasNextPage && itemCount === 0 && <Text>{emptyFilesList}</Text>}
</>
);
};
FilesListBody.defaultProps = {
listHeight: 320,
};
export default inject(({ auth }) => {
const { user } = auth.userStore;
return {
viewer: user,
};
})(observer(withTranslation("Common")(FilesListBody)));

View File

@ -0,0 +1,241 @@
import React from "react";
import { Provider as MobxProvider } from "mobx-react";
import { I18nextProvider } from "react-i18next";
import { withTranslation } from "react-i18next";
import PropTypes from "prop-types";
import throttle from "lodash/throttle";
import stores from "../../../store/index";
import i18n from "../SelectFileInput/i18n";
import SelectFileDialogModalView from "./modalView";
import SelectFileDialogAsideView from "./asideView";
import { getFiles } from "@appserver/common/api/files";
import utils from "@appserver/components/utils";
const { desktop } = utils.device;
class SelectFileDialogBody extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoadingData: false,
isVisible: false,
selectedFolder: "",
selectedFile: "",
defaultSelectedFile: "",
fileName: "",
defaultFileName: "",
filesList: [],
width: window.innerWidth,
isChecked: false,
hasNextPage: true,
isNextPageLoading: false,
displayType: this.getDisplayType(),
};
this.throttledResize = throttle(this.setDisplayType, 300);
}
componentDidMount() {
const { isPanelVisible } = this.props;
if (isPanelVisible) {
window.addEventListener("resize", this.throttledResize);
}
}
componentWillUnmount() {
if (this.throttledResize) {
this.throttledResize && this.throttledResize.cancel();
window.removeEventListener("resize", this.throttledResize);
}
}
getDisplayType = () => {
const displayType =
window.innerWidth < desktop.match(/\d+/)[0] ? "aside" : "modal";
return displayType;
};
setDisplayType = () => {
const displayType = this.getDisplayType();
this.setState({ displayType: displayType });
};
onClickInput = () => {
this.setState({
isVisible: true,
});
};
onCloseSelectFolderDialog = () => {
this.setState({
isVisible: false,
});
};
onSelectFolder = (id) => {
this.setState({
selectedFolder: id,
hasNextPage: true,
filesList: [],
});
};
onSelectFile = (e) => {
const { onSetFileName, onClose } = this.props;
const { filesList } = this.state;
const index = e.target.dataset.index;
if (!index) return;
this.setState(
{
selectedFile: filesList[index].id,
},
function () {
onClose && onClose();
onSetFileName & onSetFileName(filesList[index].title);
}
);
};
onClickFile = (e) => {
const { filesList } = this.state;
const index = +e.target.id;
this.setState({
selectedFile: filesList[index].id,
fileName: filesList[index].title,
});
};
onClickSave = () => {
const { onSetFileName, onClose, onSetFileId } = this.props;
const { fileName, selectedFile } = this.state;
onSetFileName & onSetFileName(fileName);
onSetFileId & onSetFileId(selectedFile);
onClose && onClose();
};
onCloseModalView = () => {
this.setState({
isChecked: false,
});
};
onSetLoadingData = (loading) => {
this.setState({
isLoadingData: loading,
});
};
loadNextPage = ({ startIndex = 0 }) => {
//debugger;
const { filterValue, filterType, withSubfolders } = this.props;
const { selectedFolder } = this.state;
console.log(`loadNextPage(startIndex=${startIndex}")`);
const pageCount = 30;
console.log("selectedFolder", selectedFolder);
this.setState({ isNextPageLoading: true }, () => {
getFiles(
selectedFolder,
filterType,
filterValue,
withSubfolders,
pageCount,
startIndex
)
.then((response) => {
let newFilesList = startIndex
? this.state.filesList.concat(response.files)
: response.files;
console.log("newFilesList", newFilesList);
this.setState({
hasNextPage: newFilesList.length < response.total,
isNextPageLoading: false,
filesList: newFilesList,
});
})
.catch((error) => console.log(error));
});
};
render() {
const {
t,
isPanelVisible,
onClose,
zIndex,
foldersType,
isCommonWithoutProvider,
iconUrl,
} = this.props;
const {
isVisible,
filesList,
isLoadingData,
hasNextPage,
isNextPageLoading,
selectedFolder,
displayType,
} = this.state;
return displayType === "aside" ? (
<SelectFileDialogAsideView
t={t}
isPanelVisible={isPanelVisible}
zIndex={zIndex}
onClose={onClose}
isVisible={isVisible}
isCommonWithoutProvider={isCommonWithoutProvider}
foldersType={foldersType}
filesList={filesList}
isLoadingData={isLoadingData}
onSelectFile={this.onSelectFile}
onClickInput={this.onClickInput}
onCloseSelectFolderDialog={this.onCloseSelectFolderDialog}
onSelectFolder={this.onSelectFolder}
onSetLoadingData={this.onSetLoadingData}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={this.loadNextPage}
selectedFolder={selectedFolder}
iconUrl={iconUrl}
/>
) : (
<SelectFileDialogModalView
t={t}
isPanelVisible={isPanelVisible}
onClose={onClose}
onSelectFolder={this.onSelectFolder}
onSelectFile={this.onSelectFile}
foldersType={foldersType}
onClickFile={this.onClickFile}
filesList={filesList}
isLoadingData={isLoadingData}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={this.loadNextPage}
selectedFolder={selectedFolder}
isCommonWithoutProvider={isCommonWithoutProvider}
iconUrl={iconUrl}
/>
);
}
}
const SelectFileDialogWrapper = withTranslation(["SelectFile", "Common"])(
SelectFileDialogBody
);
class SelectFileDialog extends React.Component {
render() {
return (
<MobxProvider {...stores}>
<I18nextProvider i18n={i18n}>
<SelectFileDialogWrapper {...this.props} />
</I18nextProvider>
</MobxProvider>
);
}
}
export default SelectFileDialog;

View File

@ -0,0 +1,49 @@
import React from "react";
import { StyledFilesList } from "../StyledPanels";
import { ReactSVG } from "react-svg";
import Text from "@appserver/components/text";
import config from "../../../../package.json";
const ListRow = ({
displayType,
needRowSelection,
index,
onSelectFile,
fileName,
children,
fileExst,
iconUrl,
}) => (
<StyledFilesList
displayType={displayType}
needRowSelection={needRowSelection}
>
<div
data-index={index}
className="modal-dialog_file-name"
onClick={onSelectFile}
>
<ReactSVG
src={`${config.homepage}/${iconUrl}`}
className="select-file-dialog_icon"
/>
<div data-index={index} className="files-list_full-name">
<Text data-index={index} className="entry-title">
{fileName}
</Text>
<div data-index={index} className="file-exst">
{fileExst}
</div>
</div>
<div className="files-list_file-owner_wrapper">{children}</div>
</div>
</StyledFilesList>
);
ListRow.defaultProps = {
needRowSelection: true,
};
export default ListRow;

View File

@ -0,0 +1,189 @@
import React from "react";
import { Provider as MobxProvider } from "mobx-react";
import { I18nextProvider } from "react-i18next";
import PropTypes from "prop-types";
import stores from "../../../store/index";
import i18n from "../SelectFileInput/i18n";
import { StyledAsidePanel, StyledSelectFilePanel } from "../StyledPanels";
import ModalDialog from "@appserver/components/modal-dialog";
import SelectFolderDialog from "../SelectFolderDialog";
import FolderTreeBody from "../SelectFolderDialog/folderTreeBody";
import FilesListBody from "./fileListBody";
import Button from "@appserver/components/button";
import Loader from "@appserver/components/loader";
import Text from "@appserver/components/text";
import { isArrayEqual } from "@appserver/components/utils/array";
class SelectFileDialogModalViewBody extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
};
this.backupList;
this.convertedData = [];
this.folderList = "";
}
componentDidMount() {
const { foldersType, onSetLoadingData, onSelectFolder } = this.props;
switch (foldersType) {
case "common":
this.setState({ isLoading: true }, function () {
SelectFolderDialog.getCommonFolders()
.then((commonFolder) => {
this.folderList = commonFolder;
})
.finally(() => {
onSetLoadingData && onSetLoadingData(false);
this.setState({
isLoading: false,
});
});
});
break;
case "third-party":
this.setState({ isLoading: true }, function () {
SelectFolderDialog.getCommonThirdPartyList()
.then(
(commonThirdPartyArray) =>
(this.folderList = commonThirdPartyArray)
)
.finally(() => {
onSetLoadingData && onSetLoadingData(false);
this.setState({
isLoading: false,
});
});
});
break;
}
}
onSetLoadingData = (loading) => {
this.setState({
isLoadingData: loading,
});
};
onSelect = (folder) => {
const { onSelectFolder } = this.props;
const { isLoading, selectedKeys } = this.state;
if (isArrayEqual(folder, selectedKeys)) {
return;
}
this.setState({ selectedKeys: folder });
onSelectFolder && onSelectFolder(folder[0]);
};
render() {
const {
t,
isPanelVisible,
onClose,
zIndex,
isCommonWithoutProvider,
expandedKeys,
filter,
onSelectFile,
filesList,
isLoadingData,
hasNextPage,
isNextPageLoading,
loadNextPage,
selectedFolder,
iconUrl,
} = this.props;
const { isLoading, selectedKeys } = this.state;
console.log("filesList", filesList);
return (
<StyledAsidePanel visible={isPanelVisible}>
<ModalDialog
visible={isPanelVisible}
zIndex={zIndex}
onClose={onClose}
className="select-file-modal-dialog"
style={{ maxWidth: "890px" }}
displayType="modal"
>
<ModalDialog.Header>{t("SelectFile")}</ModalDialog.Header>
<ModalDialog.Body className="select-file_body-modal-dialog">
<StyledSelectFilePanel>
{!isLoading ? (
<div className="modal-dialog_body">
<div className="modal-dialog_tree-body">
<FolderTreeBody
expandedKeys={expandedKeys}
folderList={this.folderList}
onSelect={this.onSelect}
isCommonWithoutProvider={isCommonWithoutProvider}
certainFolders
isAvailableFolders
filter={filter}
selectedKeys={selectedKeys}
/>
</div>
<div className="modal-dialog_files-body">
{selectedFolder && (
<FilesListBody
isLoadingData={isLoadingData}
filesList={filesList}
onSelectFile={onSelectFile}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={loadNextPage}
selectedFolder={selectedFolder}
iconUrl={iconUrl}
/>
)}
</div>
</div>
) : (
<div
key="loader"
className="select-file-dialog_modal-loader panel-loader-wrapper "
>
<Loader type="oval" size="16px" className="panel-loader" />
<Text as="span">{`${t("Common:LoadingProcessing")} ${t(
"Common:LoadingDescription"
)}`}</Text>
</div>
)}
</StyledSelectFilePanel>
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
className="modal-dialog-button"
primary
size="big"
label={t("Common:CloseButton")}
tabIndex={1}
onClick={onClose}
/>
</ModalDialog.Footer>
</ModalDialog>
</StyledAsidePanel>
);
}
}
class SelectFileDialogModalView extends React.Component {
render() {
return (
<MobxProvider {...stores}>
<I18nextProvider i18n={i18n}>
<SelectFileDialogModalViewBody {...this.props} />
</I18nextProvider>
</MobxProvider>
);
}
}
export default SelectFileDialogModalView;