client/src/components/pipelines/launch/dialogs/BucketBrowser.js (938 lines of code) (raw):
/*
* Copyright 2017-2019 EPAM Systems, Inc. (https://www.epam.com/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import {inject, observer} from 'mobx-react';
import connect from '../../../../utils/connect';
import {observable} from 'mobx';
import PropTypes from 'prop-types';
import SplitPane from 'react-split-pane';
import {Alert, Button, Checkbox, Col, Icon, Input, Modal, Row, Table, Tree} from 'antd';
import dataStorages from '../../../../models/dataStorage/DataStorages';
import DataStorageRequest from '../../../../models/dataStorage/DataStoragePage';
import DTSRequest from '../../../../models/dts/DTSItemsPage';
import pipelinesLibrary from '../../../../models/folders/FolderLoadTree';
import LoadingView from '../../../special/LoadingView';
import AWSRegionTag from '../../../special/AWSRegionTag';
import displayDate from '../../../../utils/displayDate';
import displaySize from '../../../../utils/displaySize';
import roleModel from '../../../../utils/roleModel';
import {
expandItem,
formatTreeItems,
generateTreeData,
getExpandedKeys,
getTreeItemByKey,
ItemTypes,
search
} from '../../model/treeStructureFunctions';
import styles from './Browser.css';
import HiddenObjects from '../../../../utils/hidden-objects';
const PAGE_SIZE = 40;
const DTS_ITEM_TYPE = 'DTS';
const DTS_ROOT_ITEM_TYPE = 'DTS-ROOT';
const S3_BUCKET_TYPE = 'S3';
const NFS_BUCKET_TYPE = 'NFS';
const AZ_BUCKET_TYPE = 'AZ';
const GS_BUCKET_TYPE = 'GS';
const OMICS_REF_BUCKET_TYPE = 'AWS_OMICS_REF';
const OMICS_SEQ_BUCKET_TYPE = 'AWS_OMICS_SEQ';
@connect({
pipelinesLibrary
})
@inject('dtsList', 'preferences')
@inject(() => ({
storages: dataStorages,
library: pipelinesLibrary
}))
@HiddenObjects.injectTreeFilter
@observer
export default class BucketBrowser extends React.Component {
static propTypes = {
path: PropTypes.string,
visible: PropTypes.bool,
onSelect: PropTypes.func,
onCancel: PropTypes.func,
multiple: PropTypes.bool,
showOnlyFolder: PropTypes.bool,
selectOnlyFiles: PropTypes.bool,
allowBucketSelection: PropTypes.bool,
checkWritePermissions: PropTypes.bool,
bucketTypes: PropTypes.arrayOf(
PropTypes.oneOf([
AZ_BUCKET_TYPE,
S3_BUCKET_TYPE,
GS_BUCKET_TYPE,
NFS_BUCKET_TYPE,
DTS_ITEM_TYPE,
OMICS_REF_BUCKET_TYPE,
OMICS_SEQ_BUCKET_TYPE
])
)
};
@observable
storage = null;
rootItems = [];
state = {
bucket: null,
path: null,
selectedItems: [],
expandedKeys: [],
selectedKeys: [],
currentPage: 0,
pageMarkers: [null],
pagePerformed: false,
search: null
};
tableData = [];
get storageIsFetching () {
if (this.storage) {
return this.storage.pending;
}
return false;
}
getRoot = (path) => {
if (!path) {
return '';
}
const pathComponents = path.split('://');
let pathCorrected = path;
if (pathComponents.length > 1) {
pathCorrected = pathComponents[1];
}
return pathCorrected.split('/')[0];
};
getBucketByPath = (path) => {
if (!this.props.storages.loaded || !this.props.dtsList.loaded) {
return null;
}
const pathCorrected = this.getRoot(path);
const storages = this.props.storages.value;
for (let i = 0; i < storages.length; i++) {
const storage = storages[i];
const storagePath = this.getRoot(storage.path);
if (pathCorrected.toLowerCase() === storagePath.toLowerCase()) {
return storage;
}
}
// check if DTS
if (path) {
for (let i = 0; i < (this.props.dtsList.value || []).length; i++) {
const dts = this.props.dtsList.value[i];
for (let j = 0; j < (dts.prefixes || []).length; j++) {
const prefix = `${dts.prefixes[j]}/`.replace(/\/\//g, '/').toLowerCase();
if (path.toLowerCase().indexOf(prefix) === 0) {
return {
...dts,
type: DTS_ROOT_ITEM_TYPE,
prefix: dts.prefixes[j]
};
}
}
}
}
return null;
};
labelsRenderer = (labels) => {
const labelsList = [];
for (let key in labels) {
if (labels.hasOwnProperty(key)) {
labelsList.push({
key: key,
value: labels[key]
});
}
}
return labelsList.map(l => (<span className={styles.label} key={l.key}>{l.value}</span>));
};
canGoToParent () {
if (this.storage) {
return this.storage.path;
}
return this.state.path;
}
removeProtocol (path) {
if (!path) {
return path;
}
const parts = path.split('://');
if (parts.length === 2) {
return parts[1];
}
return path;
}
fixPath (path) {
if (!path) {
return path;
}
if (path.endsWith('/')) {
path = path.substring(0, path.length - 1);
}
path = this.removeProtocol(path);
const parts = path.split('/');
path = parts.length > 1 ? '' : undefined;
for (let i = 1; i < parts.length; i++) {
if (i === 1) {
path += `${parts[i]}`;
} else {
path += `/${parts[i]}`;
}
}
return path;
}
parentDirectory (path) {
if (path) {
if (path.endsWith('/')) {
path = path.substring(0, path.length - 1);
}
const parts = path.split('/');
if (parts.length > 1) {
parts.pop();
return parts.join('/');
}
}
return undefined;
}
getItemFullPath = (item) => {
if (this.state.bucket && (
this.state.bucket.type === ItemTypes.storage ||
this.state.bucket.type === S3_BUCKET_TYPE ||
this.state.bucket.type === AZ_BUCKET_TYPE ||
this.state.bucket.type === GS_BUCKET_TYPE ||
this.state.bucket.type === NFS_BUCKET_TYPE ||
this.state.bucket.type === OMICS_REF_BUCKET_TYPE ||
this.state.bucket.type === OMICS_SEQ_BUCKET_TYPE
)) {
const type = this.state.bucket.storageType || this.state.bucket.type;
const buildPath = (root) => item && item.path ? `${root}/${item.path}` : root;
if (type === 'NFS') {
const storagePath = this.state.bucket.path.replace(':', '');
const mountPoint = this.state.bucket.mountPoint
? this.state.bucket.mountPoint.endsWith('/')
? this.state.bucket.mountPoint.slice(0, -1)
: this.state.bucket.mountPoint
: null;
return buildPath(mountPoint || `/cloud-data/${storagePath}`);
}
if (type === OMICS_REF_BUCKET_TYPE || type === OMICS_SEQ_BUCKET_TYPE) {
return buildPath(`${this.state.bucket.pathMask}`);
}
return buildPath(`${type.toLowerCase()}://${this.state.bucket.path}`);
} else if (this.state.bucket && this.state.bucket.type === DTS_ROOT_ITEM_TYPE) {
return item ? (item.fullPath || '') : '';
}
return item ? (item.path || '') : '';
};
itemIsSelected = (item) => {
if (this.state.selectedItems && this.state.selectedItems.length > 0) {
if (this.props.multiple) {
const filteredSelectedItems =
this.state.selectedItems.filter(selectedItem =>
selectedItem.name.trim().toLowerCase() === this.getItemFullPath(item).toLowerCase()
);
let isSelected = false;
filteredSelectedItems.forEach(selectedItem => {
if (selectedItem.type) {
isSelected = isSelected || selectedItem.type === item.type;
} else {
const filteredData = this.tableData.filter(data =>
this.getItemFullPath(data).toLowerCase() === this.getItemFullPath(item).toLowerCase()
);
if (filteredData.length > 1) {
isSelected = isSelected || item.type.toLowerCase() === 'folder';
} else {
isSelected = true;
}
}
});
return isSelected;
} else {
return this.getItemFullPath(item).toLowerCase() ===
(this.state.selectedItems[0].name || '').toLowerCase();
}
}
return false;
};
selectItem = (event, item) => {
event.stopPropagation();
if (this.props.multiple) {
const itemFullPath = this.getItemFullPath(item);
if (this.state.selectedItems && this.state.selectedItems.length > 0) {
const filteredData = this.tableData.filter(data =>
this.getItemFullPath(data).toLowerCase() === itemFullPath.toLowerCase()
);
const index = this.state.selectedItems.findIndex((selectedItem) => {
if (selectedItem.name.trim().toLowerCase() === itemFullPath.toLowerCase()) {
if (selectedItem.type) {
return selectedItem.type === item.type;
} else {
return filteredData.length > 1 ? item.type.toLowerCase() === 'folder' : true;
}
}
});
let selectedItems = this.state.selectedItems;
if (index >= 0) {
selectedItems.splice(index, 1);
} else {
selectedItems.push({name: itemFullPath, type: item.type});
}
this.setState({selectedItems: selectedItems});
} else {
this.setState({selectedItems: [{name: itemFullPath, type: item.type}]});
}
} else {
if (this.itemIsSelected(item)) {
this.setState({selectedItems: []});
} else {
this.setState({selectedItems: [{name: this.getItemFullPath(item), type: item.type}]});
}
}
};
getStorageItemsTable = () => {
const columns = [
{
key: 'selection',
title: '',
className: styles.checkboxCell,
render: (item) => {
if (item.selectable) {
return (
<Checkbox
disabled={this.props.checkWritePermissions && item.readOnly && !this.itemIsSelected(item)}
checked={this.itemIsSelected(item)}
onChange={(e) => this.selectItem(e, item)} />
);
} else {
return <span />;
}
}
},
{
dataIndex: 'type',
key: 'type',
title: '',
className: styles.itemTypeCell,
render: (text, item) => <Icon className={styles.itemType} type={item.type.toLowerCase()} />,
onCellClick: (item) => this.didSelectDataStorageItem(item)
},
{
dataIndex: 'name',
key: 'name',
title: 'Name',
className: styles.selectableCell,
onCellClick: (item) => this.didSelectDataStorageItem(item)
},
{
dataIndex: 'size',
key: 'size',
title: 'Size',
render: size => displaySize(size),
className: styles.selectableCell,
onCellClick: (item) => this.didSelectDataStorageItem(item)
},
{
dataIndex: 'changed',
key: 'changed',
title: 'Date changed',
className: styles.selectableCell,
render: (date) => date ? displayDate(date) : '',
onCellClick: (item) => this.didSelectDataStorageItem(item)
},
{
dataIndex: 'labels',
key: 'labels',
title: '',
className: styles.selectableCell,
render: this.labelsRenderer,
onCellClick: (item) => this.didSelectDataStorageItem(item)
}
];
const getList = () => {
const items = [];
if (this.canGoToParent()) {
items.push({
name: '..',
path: this.parentDirectory(this.state.path),
type: 'folder',
selectable: false
});
}
let results = [];
if (this.storage && this.storage.loaded) {
results = this.storage.value.results || [];
}
items.push(...results.map(i => {
if (this.state.bucket.type === DTS_ROOT_ITEM_TYPE) {
const path = this.storage.path ? `${this.storage.path}/${i.path}`.replace(/\/\//g, '/') : i.path;
return {
...i,
selectable: true,
fullPath: `${this.state.bucket.prefix}/${path}`.replace(/\/\//g, '/'),
path,
readOnly: this.props.checkWritePermissions && !roleModel.writeAllowed({mask: i.permission})
};
} else {
if (this.props.selectOnlyFiles) {
const selectable = i.type.toLowerCase() === 'file';
return {
...i,
selectable,
readOnly: false
};
}
return {
...i,
selectable: true,
readOnly: false
};
}
}));
return items;
};
this.tableData = this.storageIsFetching ? this.tableData : getList();
return {
columns,
data:
this.props.showOnlyFolder
? this.tableData.filter(r => r.type.toLowerCase() === 'folder')
: this.tableData
};
};
didSelectDataStorageItem = (item) => {
if (item.type.toLowerCase() === 'folder') {
this.setState({
path: decodeURIComponent(item.path || ''),
pageMarkers: [null],
pagePerformed: false,
currentPage: 0
});
}
};
bucketChanged = (key) => {
let expandedKeys = this.state.expandedKeys;
let bucket;
if (this.rootItems) {
bucket = getTreeItemByKey(key, this.rootItems);
if (bucket) {
expandItem(bucket, this.rootItems);
expandedKeys = getExpandedKeys(this.rootItems);
}
}
this.setState({
bucket: bucket,
expandedKeys,
selectedKeys: [key],
path: null
});
};
onClearSelectionClicked = () => {
this.setState({selectedItems: []});
};
onCancelClicked = () => {
if (this.props.onCancel) {
this.props.onCancel();
this.setState({selectedItems: []});
}
};
onSelectClicked = () => {
if (this.props.onSelect) {
this.props.onSelect(this.state.selectedItems.map(item => item.name).join(', '));
this.setState({selectedItems: []});
}
};
onSelectBucketClicked = () => {
if (this.props.onSelect && this.state.bucket && this.props.allowBucketSelection) {
this.props.onSelect(this.getItemFullPath());
this.setState({selectedItems: []});
}
};
renderItemTitle (item) {
let icon;
let subTitle;
switch (item.type) {
case DTS_ITEM_TYPE: icon = 'desktop'; break;
case DTS_ROOT_ITEM_TYPE: icon = 'inbox'; break;
case ItemTypes.pipeline: icon = 'fork'; break;
case ItemTypes.versionedStorage: icon = 'fork'; break;
case ItemTypes.folder: icon = 'folder'; break;
case ItemTypes.version: icon = 'tag'; break;
case ItemTypes.storage:
if (item.storageType && item.storageType.toLowerCase() !== 'nfs') {
icon = 'inbox';
} else {
icon = 'hdd';
}
subTitle = <AWSRegionTag regionId={item.regionId} />;
break;
}
let name = item.name;
if (item.searchResult) {
name = (
<span>
<span>{item.name.substring(0, item.searchResult.index)}</span>
<span className={styles.searchResult}>
{item.name.substring(item.searchResult.index, item.searchResult.index + item.searchResult.length)}
</span>
<span>{item.name.substring(item.searchResult.index + item.searchResult.length)}</span>
</span>
);
}
return (
<span
id={`pipelines-library-tree-node-${item.key}-name`}
className={styles.treeItemTitle}>
{icon && <Icon type={icon} />}<span className="storage-name">{name}</span>{subTitle}
</span>
);
}
generateTreeItems (items) {
if (!items) {
return [];
}
return formatTreeItems(items, {preferences: this.props.preferences})
.map(item => {
if (item.isLeaf) {
return (
<Tree.TreeNode
className={`pipelines-library-tree-node-${item.key}`}
title={this.renderItemTitle(item)}
key={item.key}
isLeaf={item.isLeaf} />
);
} else {
return (
<Tree.TreeNode
className={`pipelines-library-tree-node-${item.key}`}
title={this.renderItemTitle(item)}
key={item.key}
isLeaf={item.isLeaf}>
{this.generateTreeItems(item.children)}
</Tree.TreeNode>
);
}
});
}
onExpand = (expandedKeys, {expanded, node}) => {
const item = getTreeItemByKey(node.props.eventKey, this.rootItems);
if (item) {
expandItem(item, expanded);
}
this.setState({expandedKeys: getExpandedKeys(this.rootItems)});
};
onSelect = (selectedKeys, {node}) => {
const item = getTreeItemByKey(node.props.eventKey, this.rootItems);
if (item.type === ItemTypes.storage || item.type === DTS_ROOT_ITEM_TYPE) {
if (item.type === ItemTypes.storage) {
this.bucketChanged(`storage_${item.id}`);
} else {
this.bucketChanged(`${DTS_ROOT_ITEM_TYPE}_${item.id}_${item.path}`);
}
} else if (item.type === ItemTypes.folder || item.type === DTS_ITEM_TYPE) {
expandItem(item, true);
this.setState({expandedKeys: getExpandedKeys(this.rootItems)});
}
};
postprocessTree (items) {
const result = [];
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.type === ItemTypes.storage) {
result.push(item);
} else if (item.type === ItemTypes.folder && item.children && item.children.length) {
item.children = this.postprocessTree(item.children);
if (item.children.length) {
result.push(item);
}
}
}
return result;
}
generateTree () {
if (this.props.library.loaded &&
this.props.dtsList.loaded &&
!this.rootItems) {
this.rootItems = [
...(this.props.dtsList.value || [])
.filter(r => {
if (!this.props.bucketTypes || this.props.bucketTypes.length === 0) {
return true;
}
return this.props.bucketTypes.indexOf(DTS_ITEM_TYPE) >= 0;
})
.map(dtsItem => {
const parent = {
...dtsItem,
type: DTS_ITEM_TYPE,
key: `${DTS_ITEM_TYPE}_${dtsItem.id}`,
isLeaf: false,
expanded: false
};
parent.children = (dtsItem.prefixes || []).map(p => {
const name = p.split('/').filter(s => !!s).slice(-1).pop();
return {
...dtsItem,
type: DTS_ROOT_ITEM_TYPE,
key: `${DTS_ROOT_ITEM_TYPE}_${dtsItem.id}_${p}`,
isLeaf: true,
path: p,
prefix: p,
name,
parent,
expanded: false
};
});
return parent;
}),
...this.postprocessTree(
generateTreeData(
this.props.library.value,
{
types: [ItemTypes.storage],
filter: this.props.hiddenObjectsTreeFilter(
(item, type) => {
if (
!this.props.bucketTypes ||
this.props.bucketTypes.length === 0 ||
type !== ItemTypes.storage
) {
return true;
}
return this.props.bucketTypes.indexOf(item.type) >= 0;
}
)
}
)
)];
}
return (
<Tree
className={styles.libraryTree}
onSelect={this.onSelect}
onExpand={this.onExpand}
checkStrictly
expandedKeys={this.state.expandedKeys}
selectedKeys={this.state.selectedKeys} >
{this.generateTreeItems(this.rootItems)}
</Tree>
);
}
onSearchChanged = async (e) => {
await search(e, this.rootItems);
const expandedKeys = getExpandedKeys(this.rootItems);
this.setState({expandedKeys, search: e});
};
render () {
let content = <LoadingView />;
if (!this.props.storages.pending && this.props.storages.error) {
content = <Alert message="Error retrieving data storages" type="error" />;
} else if (!this.props.storages.pending) {
const table = this.getStorageItemsTable();
content = (
<SplitPane
split="vertical"
minSize={200}
pane2Style={{
overflowY: 'auto',
overflowX: 'hidden'
}}
resizerClassName="cp-split-panel-resizer"
resizerStyle={{
width: 3,
margin: '0 5px',
cursor: 'col-resize',
boxSizing: 'border-box',
backgroundClip: 'padding',
zIndex: 1
}}>
<div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
<Row>
<Input.Search onSearch={this.onSearchChanged} />
</Row>
<div style={{flex: 1, overflowY: 'auto', overflowX: 'hidden'}}>
{this.generateTree()}
</div>
</div>
{
!this.state.bucket
? <Alert type="info" message="Select data storage" />
: <div>
<Table
className={styles.table}
dataSource={table.data}
columns={table.columns}
loading={this.storageIsFetching}
rowKey="key"
pagination={false}
rowClassName={(item) => styles[item.type.toLowerCase()]}
locale={{emptyText: 'Folder is empty'}}
size="small" />
<Row key="pagination"
type="flex"
justify="end"
style={{marginTop: 10, paddingRight: 15}}>
<Button
id="prev-page-button"
onClick={this.prevPage}
disabled={this.state.currentPage === 0}
style={{margin: 3}} size="small"><Icon type="caret-left" /></Button>
<Button
id="next-page-button"
onClick={this.nextPage}
disabled={this.state.pageMarkers.length <= this.state.currentPage + 1}
style={{margin: 3}} size="small"><Icon type="caret-right" /></Button>
</Row>
</div>
}
</SplitPane>
);
}
let itemsSelectedCount = 0;
if (this.props.multiple && this.state.selectedItems) {
itemsSelectedCount = this.state.selectedItems.length;
}
return (
<Modal
width="80%"
title="Select folder or file"
closable={false}
footer={
<Row type="flex" justify="space-between">
<Col>
<Button
onClick={() => this.onClearSelectionClicked()}>Clear selection</Button>
</Col>
<Col className={styles.buttonsContainer}>
<Button
onClick={() => this.onCancelClicked()}>Cancel</Button>
<Button
type="primary"
disabled={this.state.selectedItems.length === 0}
onClick={() => this.onSelectClicked()}>
OK{
itemsSelectedCount > 0
? (itemsSelectedCount > 1 ? ` (${itemsSelectedCount} items)` : ' (1 item)')
: ''
}
</Button>
{
this.props.allowBucketSelection && (
<Button
type="primary"
disabled={
!this.state.bucket || DTS_ROOT_ITEM_TYPE === this.state.bucket.type
}
onClick={() => this.onSelectBucketClicked()}
>
Select bucket
</Button>
)
}
</Col>
</Row>
}
visible={this.props.visible}>
<Row style={{height: 450}}>
{content}
</Row>
</Modal>
);
}
componentWillReceiveProps (nextProps) {
if (nextProps.path !== this.props.path) {
let path = nextProps.path;
const allowBucketSelection = nextProps.allowBucketSelection;
const firstItemPath = (path || '').split(',').map(p => p.trim())[0];
let bucket = this.getBucketByPath(firstItemPath);
if (bucket) {
const bucketKey = bucket.type === DTS_ROOT_ITEM_TYPE
? `${DTS_ROOT_ITEM_TYPE}_${bucket.id}_${bucket.prefix}`
: `storage_${bucket.id}`;
let expandedKeys = this.state.expandedKeys;
if (this.rootItems) {
const item = getTreeItemByKey(
bucketKey,
this.rootItems
);
if (item) {
expandItem(item, this.rootItems);
expandedKeys = getExpandedKeys(this.rootItems);
}
}
let pathCorrected;
let mask;
if (bucket.type === DTS_ROOT_ITEM_TYPE) {
const prefix = `${bucket.prefix}/`.replace(/\/\//g, '/');
pathCorrected = this.parentDirectory(firstItemPath.substring(prefix.length));
} else {
pathCorrected = this.parentDirectory(this.fixPath(firstItemPath));
mask = new RegExp(`^${bucket.pathMask}(.*)$`, 'i');
}
this.setState(
{
bucket: bucket,
expandedKeys,
selectedKeys: [bucketKey],
path: decodeURIComponent(pathCorrected || ''),
selectedItems: (path || '')
.split(',')
.map(p => ({name: p.trim()}))
.filter(item => {
if (
bucket.type === DTS_ROOT_ITEM_TYPE ||
!mask ||
!allowBucketSelection
) {
return true;
}
const e = mask.exec(item.name);
if (e && e[1]) {
return !['', '/'].includes(e[1]);
}
return false;
})
});
}
}
}
prevPage = () => {
if (this.state.currentPage > 0) {
const currentPage = this.state.currentPage - 1;
const marker = this.state.pageMarkers[currentPage];
this.storage.fetchPage(marker);
this.setState({
currentPage,
pagePerformed: false
});
}
};
nextPage = () => {
if (this.state.currentPage + 1 < this.state.pageMarkers.length) {
const currentPage = this.state.currentPage + 1;
const marker = this.state.pageMarkers[currentPage];
this.storage.fetchPage(marker);
this.setState({
currentPage,
pagePerformed: false
});
}
};
performPage = () => {
const pageMarkers = this.state.pageMarkers;
if (!this.storage.error) {
if (this.storage.value.nextPageMarker) {
if (pageMarkers.length > this.state.currentPage + 1) {
pageMarkers[this.state.currentPage + 1] = this.storage.value.nextPageMarker;
} else {
pageMarkers.push(this.storage.value.nextPageMarker);
}
} else {
pageMarkers.splice(this.state.currentPage + 1, pageMarkers.length - this.state.currentPage - 1);
}
}
this.setState({
pagePerformed: true,
pageMarkers
});
};
componentDidUpdate (prevProps) {
if (this.props.storages.loaded &&
this.props.dtsList.loaded &&
!this.state.bucket &&
this.props.storages.value.length && this.props.path) {
let firstItemPath = (this.props.path || '').split(',').map(p => p.trim())[0];
let bucket = this.getBucketByPath(firstItemPath);
if (bucket && bucket.type === DTS_ROOT_ITEM_TYPE && firstItemPath) {
const prefix = bucket.prefix.replace(/\/\//g, '/');
firstItemPath = firstItemPath.substring(prefix.length);
}
let expandedKeys = this.state.expandedKeys;
if (bucket && this.rootItems) {
const item = getTreeItemByKey(
bucket.type === DTS_ROOT_ITEM_TYPE
? `${DTS_ROOT_ITEM_TYPE}_${bucket.id}_${bucket.prefix}`
: `storage_${bucket.id}`,
this.rootItems
);
if (item) {
expandItem(item, this.rootItems);
expandedKeys = getExpandedKeys(this.rootItems);
}
}
let pathCorrected;
if (bucket && bucket.type === DTS_ROOT_ITEM_TYPE) {
const prefix = `${bucket.prefix}/`.replace(/\/\//g, '/');
pathCorrected = firstItemPath.substring(prefix.length);
} else {
pathCorrected = firstItemPath;
}
pathCorrected = this.parentDirectory(pathCorrected);
if (bucket) {
this.setState({
bucket,
expandedKeys,
selectedKeys: [`storage_${bucket.id}`],
path: decodeURIComponent(pathCorrected || ''),
pageMarkers: [null],
pagePerformed: false,
currentPage: 0
});
} else if (this.state.path !== firstItemPath) {
this.setState({
selectedKeys: [],
path: decodeURIComponent(firstItemPath || ''),
pageMarkers: [null],
pagePerformed: false,
currentPage: 0
});
}
} else if (this.state.bucket &&
(this.storage === null ||
`${this.storage.id}` !== `${this.state.bucket.id}` ||
(this.storage.type === DTS_ROOT_ITEM_TYPE && `${this.storage.prefix}` !== `${this.state.bucket.prefix}`) ||
`${this.storage.type}` !== `${this.state.bucket.type}`)) {
if (this.state.bucket.type === DTS_ROOT_ITEM_TYPE) {
this.storage = new DTSRequest(this.state.bucket.id, this.state.bucket.prefix, this.state.path, PAGE_SIZE);
} else {
this.storage = new DataStorageRequest(
this.state.bucket.id,
this.state.path,
false,
false,
PAGE_SIZE
);
}
this.storage.type = this.state.bucket.type;
this.storage.fetch();
this.setState({
pageMarkers: [null],
pagePerformed: false,
currentPage: 0
});
} else if (this.storage && this.storage.path !== this.state.path) {
if (this.storage.type === DTS_ROOT_ITEM_TYPE) {
this.storage = new DTSRequest(this.state.bucket.id, this.state.bucket.prefix, this.state.path, PAGE_SIZE);
} else {
this.storage = new DataStorageRequest(
this.state.bucket.id,
this.state.path,
false,
false,
PAGE_SIZE
);
}
this.storage.type = this.state.bucket.type;
this.storage.fetch();
this.setState({
pageMarkers: [null],
pagePerformed: false,
currentPage: 0
});
} else if (this.storage && !this.storage.pending && !this.state.pagePerformed) {
this.performPage();
}
if (this.props.visible && this.props.visible !== prevProps.visible) {
this.rootItems = null;
this.props.storages.fetch();
this.props.library.fetch();
this.setState({
search: null
});
}
}
}