X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/92308b1b044dee2970c4409a0da660ccbecce945..62d3fea589acf744bb8ead4d42e11f794633704c:/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx diff --git a/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx b/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx index c9d5b65711..03d4551cab 100644 --- a/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx +++ b/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx @@ -2,14 +2,14 @@ // // SPDX-License-Identifier: AGPL-3.0 -import React from 'react'; -import classNames from 'classnames'; -import { connect } from 'react-redux'; +import React from "react"; +import classNames from "classnames"; +import { connect } from "react-redux"; import { FixedSizeList } from "react-window"; import AutoSizer from "react-virtualized-auto-sizer"; -import servicesProvider from 'common/service-provider'; -import { DownloadIcon, MoreHorizontalIcon, MoreVerticalIcon } from 'components/icon/icon'; -import { SearchInput } from 'components/search-input/search-input'; +import servicesProvider from "common/service-provider"; +import { DownloadIcon, MoreHorizontalIcon, MoreVerticalIcon } from "components/icon/icon"; +import { SearchInput } from "components/search-input/search-input"; import { ListItemIcon, StyleRulesCallback, @@ -21,25 +21,19 @@ import { Checkbox, CircularProgress, Button, -} from '@material-ui/core'; -import { FileTreeData } from '../file-tree/file-tree-data'; -import { TreeItem, TreeItemStatus } from '../tree/tree'; -import { RootState } from 'store/store'; -import { WebDAV, WebDAVRequestConfig } from 'common/webdav'; -import { AuthState } from 'store/auth/auth-reducer'; -import { extractFilesData } from 'services/collection-service/collection-service-files-response'; -import { - DefaultIcon, - DirectoryIcon, - FileIcon, - BackIcon, - SidePanelRightArrowIcon -} from 'components/icon/icon'; -import { setCollectionFiles } from 'store/collection-panel/collection-panel-files/collection-panel-files-actions'; -import { sortBy } from 'lodash'; -import { formatFileSize } from 'common/formatters'; -import { getInlineFileUrl, sanitizeToken } from 'views-components/context-menu/actions/helpers'; -import { extractUuidKind, ResourceKind } from 'models/resource'; +} from "@material-ui/core"; +import { FileTreeData } from "../file-tree/file-tree-data"; +import { TreeItem, TreeItemStatus } from "../tree/tree"; +import { RootState } from "store/store"; +import { WebDAV, WebDAVRequestConfig } from "common/webdav"; +import { AuthState } from "store/auth/auth-reducer"; +import { extractFilesData } from "services/collection-service/collection-service-files-response"; +import { DefaultIcon, DirectoryIcon, FileIcon, BackIcon, SidePanelRightArrowIcon } from "components/icon/icon"; +import { setCollectionFiles } from "store/collection-panel/collection-panel-files/collection-panel-files-actions"; +import { sortBy } from "lodash"; +import { formatFileSize } from "common/formatters"; +import { getInlineFileUrl, sanitizeToken } from "views-components/context-menu/actions/helpers"; +import { extractUuidKind, ResourceKind } from "models/resource"; export interface CollectionPanelFilesProps { isWritable: boolean; @@ -56,7 +50,8 @@ export interface CollectionPanelFilesProps { collectionPanel: any; } -type CssRules = "backButton" +type CssRules = + | "backButton" | "backButtonHidden" | "pathPanelPathWrapper" | "uploadButton" @@ -84,515 +79,634 @@ type CssRules = "backButton" const styles: StyleRulesCallback = (theme: Theme) => ({ wrapper: { - display: 'flex', - minHeight: '600px', - color: 'rgba(0,0,0,0.87)', - fontSize: '0.875rem', + display: "flex", + minHeight: "600px", + color: "rgba(0,0,0,0.87)", + fontSize: "0.875rem", fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif', fontWeight: 400, - lineHeight: '1.5', - letterSpacing: '0.01071em' + lineHeight: "1.5", + letterSpacing: "0.01071em", }, backButton: { - color: '#00bfa5', - cursor: 'pointer', - float: 'left', + color: "#00bfa5", + cursor: "pointer", + float: "left", }, backButtonHidden: { - display: 'none', + display: "none", }, dataWrapper: { - minHeight: '500px' + minHeight: "500px", }, row: { - display: 'flex', - marginTop: '0.5rem', - marginBottom: '0.5rem', - cursor: 'pointer', + display: "flex", + marginTop: "0.5rem", + marginBottom: "0.5rem", + cursor: "pointer", "&:hover": { - backgroundColor: 'rgba(0, 0, 0, 0.08)', - } + backgroundColor: "rgba(0, 0, 0, 0.08)", + }, }, rowEmpty: { - top: '40%', - width: '100%', - textAlign: 'center', - position: 'absolute' + top: "40%", + width: "100%", + textAlign: "center", + position: "absolute", }, loader: { - top: '50%', - left: '50%', - marginTop: '-15px', - marginLeft: '-15px', - position: 'absolute' + top: "50%", + left: "50%", + marginTop: "-15px", + marginLeft: "-15px", + position: "absolute", }, rowName: { - display: 'inline-flex', - flexDirection: 'column', - justifyContent: 'center' + display: "inline-flex", + flexDirection: "column", + justifyContent: "center", }, searchWrapper: { - display: 'inline-block', - marginBottom: '1rem', - marginLeft: '1rem', + display: "inline-block", + marginBottom: "1rem", + marginLeft: "1rem", }, searchWrapperHidden: { - width: '0px' + width: "0px", }, rowSelection: { - padding: '0px', + padding: "0px", }, rowActive: { color: `${theme.palette.primary.main} !important`, }, listItemIcon: { - display: 'inline-flex', - flexDirection: 'column', - justifyContent: 'center' + display: "inline-flex", + flexDirection: "column", + justifyContent: "center", }, pathPanelMenu: { - float: 'right', - marginTop: '-15px', + float: "right", + marginTop: "-15px", }, pathPanel: { - padding: '0.5rem', - marginBottom: '0.5rem', - backgroundColor: '#fff', - boxShadow: '0px 1px 3px 0px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 2px 1px -1px rgb(0 0 0 / 12%)', + padding: "0.5rem", + marginBottom: "0.5rem", + backgroundColor: "#fff", + boxShadow: "0px 1px 3px 0px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 2px 1px -1px rgb(0 0 0 / 12%)", }, pathPanelPathWrapper: { - display: 'inline-block', + display: "inline-block", }, leftPanel: { flex: 0, - padding: '0 1rem 1rem', - marginRight: '1rem', - whiteSpace: 'nowrap', - position: 'relative', - backgroundColor: '#fff', - boxShadow: '0px 3px 3px 0px rgb(0 0 0 / 20%), 0px 3px 1px 0px rgb(0 0 0 / 14%), 0px 3px 1px -1px rgb(0 0 0 / 12%)', + padding: "0 1rem 1rem", + marginRight: "1rem", + whiteSpace: "nowrap", + position: "relative", + backgroundColor: "#fff", + boxShadow: "0px 3px 3px 0px rgb(0 0 0 / 20%), 0px 3px 1px 0px rgb(0 0 0 / 14%), 0px 3px 1px -1px rgb(0 0 0 / 12%)", }, leftPanelVisible: { opacity: 1, - flex: '50%', - animation: `animateVisible 1000ms ${theme.transitions.easing.easeOut}` + flex: "50%", + animation: `animateVisible 1000ms ${theme.transitions.easing.easeOut}`, }, leftPanelHidden: { opacity: 0, - flex: 'initial', - padding: '0', - marginRight: '0', + flex: "initial", + padding: "0", + marginRight: "0", }, "@keyframes animateVisible": { "0%": { opacity: 0, - flex: 'initial', + flex: "initial", }, "100%": { opacity: 1, - flex: '50%', - } + flex: "50%", + }, }, rightPanel: { - flex: '50%', - padding: '1rem', - paddingTop: '0.5rem', - marginTop: '-0.5rem', - position: 'relative', - backgroundColor: '#fff', - boxShadow: '0px 3px 3px 0px rgb(0 0 0 / 20%), 0px 3px 1px 0px rgb(0 0 0 / 14%), 0px 3px 1px -1px rgb(0 0 0 / 12%)', + flex: "50%", + padding: "1rem", + paddingTop: "0.5rem", + marginTop: "-0.5rem", + position: "relative", + backgroundColor: "#fff", + boxShadow: "0px 3px 3px 0px rgb(0 0 0 / 20%), 0px 3px 1px 0px rgb(0 0 0 / 14%), 0px 3px 1px -1px rgb(0 0 0 / 12%)", }, pathPanelItem: { - cursor: 'pointer', + cursor: "pointer", }, uploadIcon: { - transform: 'rotate(180deg)' + transform: "rotate(180deg)", }, uploadButton: { - float: 'right', + float: "right", }, moreOptionsButton: { width: theme.spacing.unit * 3, height: theme.spacing.unit * 3, marginRight: theme.spacing.unit, - marginTop: 'auto', - marginBottom: 'auto', - justifyContent: 'center', + marginTop: "auto", + marginBottom: "auto", + justifyContent: "center", }, moreOptions: { - position: 'absolute' + position: "absolute", }, }); const pathPromise = {}; -export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState) => ({ - auth: state.auth, - collectionPanel: state.collectionPanel, - collectionPanelFiles: state.collectionPanelFiles, -}))((props: CollectionPanelFilesProps & WithStyles & { auth: AuthState }) => { - const { classes, onItemMenuOpen, onUploadDataClick, isWritable, dispatch, collectionPanelFiles, collectionPanel } = props; - const { apiToken, config } = props.auth; - - const webdavClient = new WebDAV({ - baseURL: config.keepWebServiceUrl, - headers: { - Authorization: `Bearer ${apiToken}` - }, - }); +export const CollectionPanelFiles = withStyles(styles)( + connect((state: RootState) => ({ + auth: state.auth, + collectionPanel: state.collectionPanel, + collectionPanelFiles: state.collectionPanelFiles, + }))((props: CollectionPanelFilesProps & WithStyles & { auth: AuthState }) => { + const { classes, onItemMenuOpen, onUploadDataClick, isWritable, dispatch, collectionPanelFiles, collectionPanel } = props; + const { apiToken, config } = props.auth; + + const webdavClient = new WebDAV({ + baseURL: config.keepWebServiceUrl, + headers: { + Authorization: `Bearer ${apiToken}`, + }, + }); + + const webDAVRequestConfig: WebDAVRequestConfig = { + headers: { + Depth: "1", + }, + }; - const webDAVRequestConfig: WebDAVRequestConfig = { - headers: { - Depth: '1', - }, - }; - - const parentRef = React.useRef(null); - const [path, setPath] = React.useState([]); - const [pathData, setPathData] = React.useState({}); - const [isLoading, setIsLoading] = React.useState(false); - const [leftSearch, setLeftSearch] = React.useState(''); - const [rightSearch, setRightSearch] = React.useState(''); - - const leftKey = (path.length > 1 ? path.slice(0, path.length - 1) : path).join('/'); - const rightKey = path.join('/'); - - const leftData = pathData[leftKey] || []; - const rightData = pathData[rightKey]; - - React.useEffect(() => { - if (props.currentItemUuid && extractUuidKind(props.currentItemUuid) === ResourceKind.COLLECTION) { - setPathData({}); - setPath([props.currentItemUuid]); - } - }, [props.currentItemUuid]); - - const fetchData = (keys, ignoreCache = false) => { - const keyArray = Array.isArray(keys) ? keys : [keys]; - - Promise.all(keyArray.filter(key => !!key) - .map((key) => { - const dataExists = !!pathData[key]; - const runningRequest = pathPromise[key]; - - if (ignoreCache || (!dataExists && !runningRequest)) { - if (!isLoading) { - setIsLoading(true); - } + const parentRef = React.useRef(null); + const [path, setPath] = React.useState([]); + const [pathData, setPathData] = React.useState({}); + const [isLoading, setIsLoading] = React.useState(false); + const [leftSearch, setLeftSearch] = React.useState(""); + const [rightSearch, setRightSearch] = React.useState(""); - pathPromise[key] = true; + const leftKey = (path.length > 1 ? path.slice(0, path.length - 1) : path).join("/"); + const rightKey = path.join("/"); - return webdavClient.propfind(`c=${key}`, webDAVRequestConfig); - } + const leftData = pathData[leftKey] || []; + const rightData = pathData[rightKey]; - return Promise.resolve(null); - }) - .filter((promise) => !!promise) - ) - .then((requests) => { - const newState = requests.map((request, index) => { - if (request && request.responseXML != null) { - const key = keyArray[index]; - const result: any = extractFilesData(request.responseXML); - const sortedResult = sortBy(result, (n) => n.name).sort((n1, n2) => { - if (n1.type === 'directory' && n2.type !== 'directory') { - return -1; + React.useEffect(() => { + if (props.currentItemUuid && extractUuidKind(props.currentItemUuid) === ResourceKind.COLLECTION) { + setPathData({}); + setPath([props.currentItemUuid]); + } + }, [props.currentItemUuid]); + + const fetchData = (keys, ignoreCache = false) => { + const keyArray = Array.isArray(keys) ? keys : [keys]; + + Promise.all( + keyArray + .filter(key => !!key) + .map(key => { + const dataExists = !!pathData[key]; + const runningRequest = pathPromise[key]; + + if (ignoreCache || (!dataExists && !runningRequest)) { + if (!isLoading) { + setIsLoading(true); } - if (n1.type !== 'directory' && n2.type === 'directory') { - return 1; + + pathPromise[key] = true; + + return webdavClient.propfind(`c=${key}`, webDAVRequestConfig); + } + + return Promise.resolve(null); + }) + .filter(promise => !!promise) + ) + .then(requests => { + const newState = requests + .map((request, index) => { + if (request && request.responseXML != null) { + const key = keyArray[index]; + const result: any = extractFilesData(request.responseXML); + const sortedResult = sortBy(result, n => n.name).sort((n1, n2) => { + if (n1.type === "directory" && n2.type !== "directory") { + return -1; + } + if (n1.type !== "directory" && n2.type === "directory") { + return 1; + } + return 0; + }); + + return { [key]: sortedResult }; } - return 0; - }); + return {}; + }) + .reduce((prev, next) => { + return { ...next, ...prev }; + }, {}); + setPathData(state => ({ ...state, ...newState })); + }, () => { + // Nothing to do + }) + .finally(() => { + setIsLoading(false); + keyArray.forEach(key => delete pathPromise[key]); + }); + }; - return { [key]: sortedResult }; - } - return {}; - }).reduce((prev, next) => { - return { ...next, ...prev }; - }, {}); - setPathData((state) => ({ ...state, ...newState })); - }) - .finally(() => { - setIsLoading(false); - keyArray.forEach(key => delete pathPromise[key]); - }); - }; - - React.useEffect(() => { - if (rightKey) { - fetchData(rightKey); - setLeftSearch(''); - setRightSearch(''); - } - }, [rightKey, rightData]); // eslint-disable-line react-hooks/exhaustive-deps - - const currentPDH = (collectionPanel.item || {}).portableDataHash; - React.useEffect(() => { - if (currentPDH) { - fetchData([leftKey, rightKey], true); - } - }, [currentPDH]); // eslint-disable-line react-hooks/exhaustive-deps - - React.useEffect(() => { - if (rightData) { - const filtered = rightData.filter(({ name }) => name.indexOf(rightSearch) > -1); - setCollectionFiles(filtered, false)(dispatch); - } - }, [rightData, dispatch, rightSearch]); - - const handleRightClick = React.useCallback( - (event) => { - event.preventDefault(); - let elem = event.target; - - while (elem && elem.dataset && !elem.dataset.item) { - elem = elem.parentNode; + React.useEffect(() => { + if (rightKey) { + fetchData(rightKey); + setLeftSearch(""); + setRightSearch(""); } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [rightKey, rightData]); - if (!elem || !elem.dataset) { - return; + const currentPDH = (collectionPanel.item || {}).portableDataHash; + React.useEffect(() => { + if (currentPDH) { + fetchData([leftKey, rightKey], true); } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPDH]); - const { id } = elem.dataset; + React.useEffect(() => { + if (rightData) { + const filtered = rightData.filter(({ name }) => name.indexOf(rightSearch) > -1); + setCollectionFiles(filtered, false)(dispatch); + } + }, [rightData, dispatch, rightSearch]); - const item: any = { - id, - data: rightData.find((elem) => elem.id === id), - }; + const handleRightClick = React.useCallback( + event => { + event.preventDefault(); + let elem = event.target; - if (id) { - onItemMenuOpen(event, item, isWritable); - } - }, - [onItemMenuOpen, isWritable, rightData]); + while (elem && elem.dataset && !elem.dataset.item) { + elem = elem.parentNode; + } - React.useEffect(() => { - let node = null; + if (!elem || !elem.dataset) { + return; + } - if (parentRef?.current) { - node = parentRef.current; - (node as any).addEventListener('contextmenu', handleRightClick); - } + const { id } = elem.dataset; - return () => { - if (node) { - (node as any).removeEventListener('contextmenu', handleRightClick); - } - }; - }, [parentRef, handleRightClick]); + const item: any = { + id, + data: rightData.find(elem => elem.id === id), + }; - const handleClick = React.useCallback( - (event: any) => { - let isCheckbox = false; - let isMoreButton = false; - let elem = event.target; + if (id) { + onItemMenuOpen(event, item, isWritable); + } + }, + [onItemMenuOpen, isWritable, rightData] + ); - if (elem.type === 'checkbox') { - isCheckbox = true; - } - // The "More options" button click event could be triggered on its - // internal graphic element. - else if ((elem.dataset && elem.dataset.id === 'moreOptions') || (elem.parentNode && elem.parentNode.dataset && elem.parentNode.dataset.id === 'moreOptions')) { - isMoreButton = true; - } + React.useEffect(() => { + let node = null; - while (elem && elem.dataset && !elem.dataset.item) { - elem = elem.parentNode; + if (parentRef?.current) { + node = parentRef.current; + (node as any).addEventListener("contextmenu", handleRightClick); } - if (elem && elem.dataset && !isCheckbox && !isMoreButton) { - const { parentPath, subfolderPath, breadcrumbPath, type } = elem.dataset; - - if (breadcrumbPath) { - const index = path.indexOf(breadcrumbPath); - setPath((state) => ([...state.slice(0, index + 1)])); + return () => { + if (node) { + (node as any).removeEventListener("contextmenu", handleRightClick); } + }; + }, [parentRef, handleRightClick]); - if (parentPath && type === 'directory') { - if (path.length > 1) { - path.pop() - } + const handleClick = React.useCallback( + (event: any) => { + let isCheckbox = false; + let isMoreButton = false; + let elem = event.target; - setPath((state) => ([...state, parentPath])); + if (elem.type === "checkbox") { + isCheckbox = true; } - - if (subfolderPath && type === 'directory') { - setPath((state) => ([...state, subfolderPath])); + // The "More options" button click event could be triggered on its + // internal graphic element. + else if ( + (elem.dataset && elem.dataset.id === "moreOptions") || + (elem.parentNode && elem.parentNode.dataset && elem.parentNode.dataset.id === "moreOptions") + ) { + isMoreButton = true; } - if (elem.dataset.id && type === 'file') { - const item = rightData.find(({ id }) => id === elem.dataset.id) || leftData.find(({ id }) => id === elem.dataset.id); - const enhancedItem = servicesProvider.getServices().collectionService.extendFileURL(item); - const fileUrl = sanitizeToken(getInlineFileUrl(enhancedItem.url, config.keepWebServiceUrl, config.keepWebInlineServiceUrl), true); - window.open(fileUrl, '_blank'); + while (elem && elem.dataset && !elem.dataset.item) { + elem = elem.parentNode; } - } - if (isCheckbox) { - const { id } = elem.dataset; - const item = collectionPanelFiles[id]; - props.onSelectionToggle(event, item); - } - if (isMoreButton) { - const { id } = elem.dataset; - const item: any = { - id, - data: rightData.find((elem) => elem.id === id), - }; - onItemMenuOpen(event, item, isWritable); - } - }, - [path, setPath, collectionPanelFiles] // eslint-disable-line react-hooks/exhaustive-deps - ); - - const getItemIcon = React.useCallback( - (type: string, activeClass: string | null) => { - let Icon = DefaultIcon; - - switch (type) { - case 'directory': - Icon = DirectoryIcon; - break; - case 'file': - Icon = FileIcon; - break; - } + if (elem && elem.dataset && !isCheckbox && !isMoreButton) { + const { parentPath, subfolderPath, breadcrumbPath, type } = elem.dataset; - return ( - - - - ) - }, - [classes] - ); + if (breadcrumbPath) { + const index = path.indexOf(breadcrumbPath); + setPath(state => [...state.slice(0, index + 1)]); + } - const getActiveClass = React.useCallback( - (name) => { - return path[path.length - 1] === name ? classes.rowActive : null; - }, - [path, classes] - ); + if (parentPath && type === "directory") { + if (path.length > 1) { + path.pop(); + } - const onOptionsMenuOpen = React.useCallback( - (ev, isWritable) => { - props.onOptionsMenuOpen(ev, isWritable); - }, - [props.onOptionsMenuOpen] // eslint-disable-line react-hooks/exhaustive-deps - ); - - return
-
-
- {path.map((p: string, index: number) => - - {index === 0 ? 'Home' : p} /  - ) + setPath(state => [...state, parentPath]); + } + + if (subfolderPath && type === "directory") { + setPath(state => [...state, subfolderPath]); + } + + if (elem.dataset.id && type === "file") { + const item = rightData.find(({ id }) => id === elem.dataset.id) || leftData.find(({ id }) => id === elem.dataset.id); + const enhancedItem = servicesProvider.getServices().collectionService.extendFileURL(item); + const fileUrl = sanitizeToken( + getInlineFileUrl(enhancedItem.url, config.keepWebServiceUrl, config.keepWebInlineServiceUrl), + true + ); + window.open(fileUrl, "_blank", "noopener"); + } } -
- - { - onOptionsMenuOpen(ev, isWritable); - }}> - - - -
-
-
1 ? classes.leftPanelVisible : classes.leftPanelHidden)} data-cy="collection-files-left-panel"> - 1 ? classes.backButton : classes.backButtonHidden}> - setPath((state) => ([...state.slice(0, state.length - 1)]))}> - - - -
1 ? classes.searchWrapper : classes.searchWrapperHidden}> - -
-
{leftData - ? {({ height, width }) => { - const filtered = leftData.filter(({ name }) => name.indexOf(leftSearch) > -1); - return !!filtered.length - ? {({ index, style }) => { - const { id, type, name } = filtered[index]; - return
- {getItemIcon(type, getActiveClass(name))} -
- {name} -
- {getActiveClass(name) - ? - : null - } -
; - }}
- :
No directories available
- }} -
- :
} -
-
-
-
- + + if (isCheckbox) { + const { id } = elem.dataset; + const item = collectionPanelFiles[id]; + props.onSelectionToggle(event, item); + } + if (isMoreButton) { + const { id } = elem.dataset; + const item: any = { + id, + data: rightData.find(elem => elem.id === id), + }; + onItemMenuOpen(event, item, isWritable); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [path, setPath, collectionPanelFiles] + ); + + const getItemIcon = React.useCallback( + (type: string, activeClass: string | null) => { + let Icon = DefaultIcon; + + switch (type) { + case "directory": + Icon = DirectoryIcon; + break; + case "file": + Icon = FileIcon; + break; + } + + return ( + + + + ); + }, + [classes] + ); + + const getActiveClass = React.useCallback( + name => { + return path[path.length - 1] === name ? classes.rowActive : null; + }, + [path, classes] + ); + + const onOptionsMenuOpen = React.useCallback( + (ev, isWritable) => { + props.onOptionsMenuOpen(ev, isWritable); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [props.onOptionsMenuOpen] + ); + + return ( +
+
+
+ {path.map((p: string, index: number) => ( + + {index === 0 ? "Home" : p} /  + + ))} +
+ + { + onOptionsMenuOpen(ev, isWritable); + }} + > + + +
- {isWritable && - } -
{rightData && !isLoading - ? {({ height, width }) => { - const filtered = rightData.filter(({ name }) => name.indexOf(rightSearch) > -1); - return !!filtered.length - ? {({ index, style }) => { - const { id, type, name, size } = filtered[index]; - - return
-   - {getItemIcon(type, null)} -
- {name} -
- - {formatFileSize(size)} - - - - - - -
- }}
- :
This collection is empty
- }}
- :
- -
} +
+
1 ? classes.leftPanelVisible : classes.leftPanelHidden)} + data-cy="collection-files-left-panel" + > + 1 ? classes.backButton : classes.backButtonHidden} + > + setPath(state => [...state.slice(0, state.length - 1)])}> + + + +
1 ? classes.searchWrapper : classes.searchWrapperHidden}> + +
+
+ {leftData ? ( + + {({ height, width }) => { + const filtered = leftData.filter(({ name }) => name.indexOf(leftSearch) > -1); + return !!filtered.length ? ( + + {({ index, style }) => { + const { id, type, name } = filtered[index]; + return ( +
+ {getItemIcon(type, getActiveClass(name))} +
{name}
+ {getActiveClass(name) ? ( + + ) : null} +
+ ); + }} +
+ ) : ( +
No directories available
+ ); + }} +
+ ) : ( +
+ +
+ )} +
+
+
+
+ +
+ {isWritable && ( + + )} +
+ {rightData && !isLoading ? ( + + {({ height, width }) => { + const filtered = rightData.filter(({ name }) => name.indexOf(rightSearch) > -1); + return !!filtered.length ? ( + + {({ index, style }) => { + const { id, type, name, size } = filtered[index]; + + return ( +
+ +   + {getItemIcon(type, null)} +
{name}
+ + {formatFileSize(size)} + + + + + + +
+ ); + }} +
+ ) : ( +
This collection is empty
+ ); + }} +
+ ) : ( +
+ +
+ )} +
+
-
-
-})); + ); + }) +);