Skip to content

Commit

Permalink
Launch form: allow uploading local files as path parameters (#3868)
Browse files Browse the repository at this point in the history
  • Loading branch information
rodichenko committed Jan 20, 2025
1 parent 4f695f6 commit de78430
Show file tree
Hide file tree
Showing 15 changed files with 1,084 additions and 29 deletions.
4 changes: 3 additions & 1 deletion client/src/components/main/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import CurrentUserAttributes, {
import CloudPipelineThemes from '../../themes';
import ApplicationInfo from '../../models/utils/application-info';
import SystemJobs from '../../utils/system-jobs';
import uiLaunchParametersConfiguration from '../../utils/ui-launch-parameters-configuration';

const routing = new RouterStore();
const history = syncHistoryWithStore(hashHistory, routing);
Expand Down Expand Up @@ -170,7 +171,8 @@ const Root = () =>
vsActions,
themes,
applicationInfo,
systemJobs
systemJobs,
uiLaunchParametersConfiguration
}}>
<AppRouter />
</Provider>;
Expand Down
157 changes: 143 additions & 14 deletions client/src/components/pipelines/launch/dialogs/BucketBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
import React from 'react';
import {inject, observer} from 'mobx-react';
import connect from '../../../../utils/connect';
import {observable} from 'mobx';
import {computed, 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 {Alert, Button, Checkbox, Col, Icon, Input, Modal, Row, Table, Tree, message} from 'antd';
import dataStorages from '../../../../models/dataStorage/DataStorages';
import DataStorageRequest from '../../../../models/dataStorage/DataStoragePage';
import DTSRequest from '../../../../models/dts/DTSItemsPage';
Expand All @@ -42,6 +42,9 @@ import {

import styles from './Browser.css';
import HiddenObjects from '../../../../utils/hidden-objects';
import UploadFilesArea from './upload-files-area';
import FileUploadList from '../../../../utils/files-upload/file-upload-list';
import UploadFilesList from './upload-files-list';

const PAGE_SIZE = 40;
const DTS_ITEM_TYPE = 'DTS';
Expand All @@ -57,7 +60,7 @@ const OMICS_SEQ_BUCKET_TYPE = 'AWS_OMICS_SEQ';
@connect({
pipelinesLibrary
})
@inject('dtsList', 'preferences')
@inject('dtsList', 'preferences', 'uiLaunchParametersConfiguration')
@inject(() => ({
storages: dataStorages,
library: pipelinesLibrary
Expand Down Expand Up @@ -85,7 +88,8 @@ export default class BucketBrowser extends React.Component {
OMICS_REF_BUCKET_TYPE,
OMICS_SEQ_BUCKET_TYPE
])
)
),
uploadFilesAllowed: PropTypes.bool
};

@observable
Expand All @@ -101,11 +105,21 @@ export default class BucketBrowser extends React.Component {
currentPage: 0,
pageMarkers: [null],
pagePerformed: false,
search: null
search: null,
uploadedFiles: [],
uploading: undefined
};

tableData = [];

@computed
get uploadFilesEnabled () {
const {uiLaunchParametersConfiguration, uploadFilesAllowed} = this.props;
return uploadFilesAllowed &&
uiLaunchParametersConfiguration &&
uiLaunchParametersConfiguration.localFiles.enabled;
}

get storageIsFetching () {
if (this.storage) {
return this.storage.pending;
Expand Down Expand Up @@ -477,9 +491,59 @@ export default class BucketBrowser extends React.Component {
};

onSelectClicked = () => {
if (this.props.onSelect) {
this.props.onSelect(this.state.selectedItems.map(item => item.name).join(', '));
this.setState({selectedItems: []});
const {
uploadedFiles,
selectedItems
} = this.state;
const result = selectedItems.slice().map((item) => item.name);
const onFinish = (uploaded = []) => {
if (this.props.onSelect) {
this.props.onSelect(result.concat(uploaded).join(', '));
this.setState({selectedItems: []});
}
};
const {uiLaunchParametersConfiguration} = this.props;
if (
uploadedFiles.length > 0 &&
uiLaunchParametersConfiguration &&
uiLaunchParametersConfiguration.localFiles &&
uiLaunchParametersConfiguration.localFiles.enabled &&
uiLaunchParametersConfiguration.localFiles.dataStorage &&
uiLaunchParametersConfiguration.localFiles.dataStoragePathGenerator
) {
const session = new FileUploadList(
uploadedFiles,
uiLaunchParametersConfiguration.localFiles.dataStorage.id,
uiLaunchParametersConfiguration.localFiles.dataStoragePathGenerator()
);
this.setState({uploading: session}, async () => {
const hide = message.loading('Uploading files...', 0);
try {
await session.upload();
const {
done,
aborted,
hasErrors,
files = []
} = session.getState();
if (aborted) {
return;
}
if (!done || hasErrors) {
throw new Error('Error uploading files');
}
session.destroy();
this.setState({
uploading: undefined
}, () => onFinish(files.map((f) => f.resolvedPath).filter(Boolean)));
} catch (error) {
message.error(error.message, 5);
} finally {
hide();
}
});
} else {
onFinish();
}
};

Expand Down Expand Up @@ -672,7 +736,42 @@ export default class BucketBrowser extends React.Component {
this.setState({expandedKeys, search: e});
};

onUploadedFilesChanged = (uploadedFiles = []) => {
this.setState({uploadedFiles});
};

onAbortUpload = () => {
const {uploading} = this.state;
if (uploading) {
(uploading.abort)();
this.setState({uploading: undefined});
this.onCancelClicked();
}
};

render () {
const {
uploadFilesEnabled
} = this;
const {
uploading
} = this.state;
if (uploading) {
return (
<Modal
width="80%"
title="Uploading files..."
closable={false}
footer={
<Row type="flex" justify="end">
<Button onClick={this.onAbortUpload}>Cancel</Button>
</Row>
}
visible={this.props.visible}>
<UploadFilesList session={uploading} />
</Modal>
);
}
let content = <LoadingView />;
if (!this.props.storages.pending && this.props.storages.error) {
content = <Alert message="Error retrieving data storages" type="error" />;
Expand Down Expand Up @@ -740,9 +839,9 @@ export default class BucketBrowser extends React.Component {

let itemsSelectedCount = 0;
if (this.props.multiple && this.state.selectedItems) {
itemsSelectedCount = this.state.selectedItems.length;
itemsSelectedCount += this.state.selectedItems.length;
}

itemsSelectedCount += this.state.uploadedFiles.length;
return (
<Modal
width="80%"
Expand All @@ -759,7 +858,10 @@ export default class BucketBrowser extends React.Component {
onClick={() => this.onCancelClicked()}>Cancel</Button>
<Button
type="primary"
disabled={this.state.selectedItems.length === 0}
disabled={
this.state.selectedItems.length === 0 &&
this.state.uploadedFiles.length === 0
}
onClick={() => this.onSelectClicked()}>
OK{
itemsSelectedCount > 0
Expand All @@ -784,9 +886,29 @@ export default class BucketBrowser extends React.Component {
</Row>
}
visible={this.props.visible}>
<Row style={{height: 450}}>
{content}
</Row>
<div style={{height: 450, display: 'flex'}}>
<div
style={{
flex: 1,
height: '100%',
overflow: 'auto',
display: 'flex',
position: 'relative'
}}
>
{content}
</div>
{
uploadFilesEnabled && (
<UploadFilesArea
style={{width: 300, height: '100%', overflow: 'auto', marginLeft: 5}}
files={this.state.uploadedFiles}
onFilesChange={this.onUploadedFilesChanged}
multiple={this.props.multiple}
/>
)
}
</div>
</Modal>
);
}
Expand Down Expand Up @@ -996,6 +1118,13 @@ export default class BucketBrowser extends React.Component {
this.setState({
search: null
});
this.resetUploadedFilesList();
}
}

resetUploadedFilesList = () => {
this.setState({
uploadedFiles: []
});
};
}
Loading

0 comments on commit de78430

Please sign in to comment.