Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUI Library: show current folder size (metadata panel) for datastorages #3776

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
23 changes: 17 additions & 6 deletions client/src/components/pipelines/browser/data-storage/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 EPAM Systems, Inc. (https://www.epam.com/)
* Copyright 2017-2024 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.
Expand Down Expand Up @@ -89,7 +89,7 @@ import {
import {
METADATA_KEY as REQUEST_DAV_ACCESS_ATTRIBUTE
} from '../../../special/metadata/special/request-dav-access';
import StorageSize from '../../../special/storage-size';
import StorageSize, {MODE as STORAGE_SIZE_MODE} from '../../../special/storage-size';
import highlightText from '../../../special/highlightText';
import {extractFileShareMountList} from '../forms/DataStoragePathInput';
import SharedItemInfo from '../forms/data-storage-item-sharing/SharedItemInfo';
Expand Down Expand Up @@ -190,7 +190,8 @@ export default class DataStorage extends React.Component {
previewPending: false,
restorePending: false,
omicsDialogVisible: false,
importedJobs: false
importedJobs: false,
storageSizeMode: STORAGE_SIZE_MODE.storage
};

@observable storage = new DataStorageListing({
Expand Down Expand Up @@ -2640,6 +2641,10 @@ export default class DataStorage extends React.Component {
}
};

onStorageSizeModeChange = (mode) => {
this.setState({storageSizeMode: mode});
};

renderPresentationConfiguration = () => {
const metadataAction = {
key: 'attributes',
Expand Down Expand Up @@ -2764,7 +2769,6 @@ export default class DataStorage extends React.Component {
mask,
policySupported
} = this.storage.info || {};

const restoreClassChangeDisclaimer = (item, operation) => {
if (!item) {
return '';
Expand Down Expand Up @@ -2977,7 +2981,10 @@ export default class DataStorage extends React.Component {
(/^nfs$/i.test(type) && !this.isOmicsStore)
? FS_MOUNTS_NOTIFICATIONS_ATTRIBUTE
: false,
((!/^nfs$/i.test(type) && !this.state.selectedFile) && !this.isOmicsStore)
((!/^nfs$/i.test(type) && !this.state.selectedFile) &&
!this.isOmicsStore &&
this.state.storageSizeMode === STORAGE_SIZE_MODE.storage
)
? REQUEST_DAV_ACCESS_ATTRIBUTE
: false
].filter(Boolean)}
Expand All @@ -2993,7 +3000,11 @@ export default class DataStorage extends React.Component {
this.userLifeCyclePermissions.write
)}
/>,
<StorageSize storage={this.storage.info} />
<StorageSize
storage={this.storage.info}
path={this.props.path}
onModeChange={this.onStorageSizeModeChange}
/>
] : []}
specialTagsProperties={{
storageType: this.fileShareMount ? this.fileShareMount.mountType : undefined,
Expand Down
155 changes: 112 additions & 43 deletions client/src/components/special/storage-size/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 EPAM Systems, Inc. (https://www.epam.com/)
* Copyright 2017-2024 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.
Expand All @@ -21,7 +21,8 @@ import {
message,
Tooltip,
Icon,
Modal
Modal,
Spin
} from 'antd';
import {computed, observable} from 'mobx';
import {inject, observer} from 'mobx-react';
Expand All @@ -38,6 +39,16 @@ const STORAGE_DESCRIPTION = {
DEEP_ARCHIVE: 'Deep archive'
};

export const MODE = {
storage: 'storage',
folder: 'folder'
};

const modeToggler = {
[MODE.storage]: MODE.folder,
[MODE.folder]: MODE.storage
};

const REFRESH_REQUESTED_MESSAGE =
'Storage size refresh has been requested. Please wait a couple of minutes.';

Expand Down Expand Up @@ -88,21 +99,24 @@ function InfoTooltip ({sizes, isNFS}) {
@observer
class StorageSize extends React.PureComponent {
state = {
showDetailedInfo: false
showDetailedInfo: false,
mode: MODE.storage,
pending: false
};

@observable info;

componentDidMount () {
this.updateStorageSize();
this.updateMode();
}

componentDidUpdate (prevProps, prevState, snapshot) {
if (
prevProps.path !== this.props.path ||
prevProps.storage !== this.props.storage ||
prevProps.storageId !== this.props.storageId
) {
this.updateStorageSize();
this.updateMode();
}
}

Expand Down Expand Up @@ -169,26 +183,46 @@ class StorageSize extends React.PureComponent {
return (storage.type || '').toUpperCase() === 'NFS';
}

updateStorageSize = async () => {
get isRoot () {
return !this.props.path;
}

updateMode = () => {
const {path, onModeChange} = this.props;
this.setState({mode: path ? MODE.folder : MODE.storage}, () => {
this.updateStorageSize();
onModeChange && onModeChange(this.state.mode);
});
};

updateStorageSize = () => {
const {mode} = this.state;
const {
storage,
storageId
storageId,
path: pathProp
} = this.props;
let id = storageId;
if (id === undefined && typeof storage === 'object') {
id = storage.id;
}
if (id !== undefined) {
const request = new DataStoragePathUsage(id);
await request.fetch();
if (request.error) {
console.warn(request.error);
this.info = null;
} else if (request.value) {
this.info = request.value;
} else {
this.info = null;
}
this.setState({pending: true}, async () => {
const path = mode === MODE.folder
? pathProp
: undefined;
const request = new DataStoragePathUsage(id, path);
await request.fetch();
if (request.error) {
console.warn(request.error);
this.info = null;
} else if (request.value) {
this.info = request.value;
} else {
this.info = null;
}
this.setState({pending: false});
});
}
};

Expand Down Expand Up @@ -226,6 +260,8 @@ class StorageSize extends React.PureComponent {
};

renderInfo = () => {
const {mode} = this.state;
const {path, storage} = this.props;
const {
size,
effective,
Expand All @@ -249,8 +285,21 @@ class StorageSize extends React.PureComponent {
const previousVersionsInfo = this.isNFS
? ''
: ` (${previousVersionsSize})`;
let header = storage?.name || storage?.path || 'Storage';
if (mode === MODE.folder) {
header = (path || '').split('/').pop();
}
const getIcon = () => {
if (mode === MODE.storage) {
return this.isNFS ? 'hdd' : 'inbox';
}
return 'folder';
};
return (
<div className={styles.detailsContainer}>
<b className={styles.folderSizeTitle}>
<Icon type={getIcon()} /> {header}
</b>
<div className={styles.standardContainer}>
<div
className={styles.standardDetailRow}
Expand All @@ -261,14 +310,13 @@ class StorageSize extends React.PureComponent {
</span>
<InfoTooltip isNFS={this.isNFS} sizes={{size, effective}} />
</div>
{this.isNFS ? this.renderControls() : null}
</div>
{this.hasArchivedData ? (
<span className={styles.detail}>
Archive size: {`${totalArchiveSize} (${archivePreviousVersionsSize})`}
</span>
) : null}
{this.isNFS ? null : this.renderControls()}
{this.renderControls()}
</div>
);
};
Expand Down Expand Up @@ -369,8 +417,30 @@ class StorageSize extends React.PureComponent {
};

renderControls = () => {
const {mode} = this.state;
const {onModeChange} = this.props;
const toggleMode = () => this.setState({mode: modeToggler[mode]}, () => {
onModeChange && onModeChange(this.state.mode);
this.updateStorageSize();
});
return (
<div>
{!this.isRoot ? (
<a
className={styles.controlsButton}
onClick={toggleMode}
>
Show {modeToggler[mode]} size
</a>
) : null}
{this.isRoot || mode === MODE.storage ? (
<a
className={styles.controlsButton}
onClick={this.refreshSize}
>
Re-index
</a>
) : null}
{this.hasArchivedData && this.usageInfo?.details?.length > 0 ? (
<a
className={styles.controlsButton}
Expand All @@ -379,36 +449,33 @@ class StorageSize extends React.PureComponent {
Show details
</a>
) : null}
<a
className={styles.controlsButton}
onClick={this.refreshSize}
>
Re-index
</a>
</div>
);
};

render () {
const {pending} = this.state;
const {className, style} = this.props;
if (
this.usageInfo &&
(this.usageInfo.size || this.usageInfo.archiveSizeTotal)
) {
if (this.usageInfo && (
this.usageInfo.size !== undefined ||
this.usageInfo.archiveSizeTotal !== undefined
)) {
return (
<div
className={
classNames(
styles.storageSizeContainer,
'cp-text',
className
)
}
style={style}
>
{this.renderInfo()}
{this.renderDetailedInfoModal()}
</div>
<Spin spinning={pending}>
<div
className={
classNames(
styles.storageSizeContainer,
'cp-text',
className
)
}
style={style}
>
{this.renderInfo()}
{this.renderDetailedInfoModal()}
</div>
</Spin>
);
}
return (
Expand Down Expand Up @@ -436,7 +503,9 @@ StorageSize.propTypes = {
className: PropTypes.string,
storage: PropTypes.object,
storageId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
style: PropTypes.object
style: PropTypes.object,
path: PropTypes.string,
onModeChange: PropTypes.func
};

export default StorageSize;
9 changes: 8 additions & 1 deletion client/src/components/special/storage-size/storage-size.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 EPAM Systems, Inc. (https://www.epam.com/)
* Copyright 2017-2024 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.
Expand Down Expand Up @@ -89,3 +89,10 @@
.detailed-info-grid-row .total {
grid-area: total;
}

.folder-size-title {
word-break: break-all;
display: flex;
align-items: center;
gap: 3px;
}
4 changes: 2 additions & 2 deletions client/src/models/dataStorage/DataStoragePathUsage.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
import Remote from '../basic/Remote';

export default class DataStoragePathUsage extends Remote {
constructor (storage) {
constructor (storage, path = '') {
super();
this.url = `/datastorage/path/usage?id=${storage}`;
this.url = `/datastorage/path/usage?id=${storage}${path.length > 0 ? `&path=${path}` : ''}`;
}
}
Loading