This repository has been archived on 2025-09-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
repertory-ui/src/containers/MountItems/MountItems.js
2020-02-13 14:08:11 -06:00

414 lines
14 KiB
JavaScript

import React from 'react';
import AddRemoteMount from '../AddRemoteMount/AddRemoteMount';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import {connect} from 'react-redux';
import './MountItems.css';
import Modal from '../../components/UI/Modal/Modal';
import MountItem from './MountItem/MountItem';
import IPCContainer from '../IPCContainer/IPCContainer';
import {
resetMountsState,
setAllowMount,
setAutoMountProcessed,
setBusy,
setMounted,
setMountState,
setProviderState
} from '../../redux/actions/mount_actions';
import {notifyError} from '../../redux/actions/error_actions';
const Constants = require('../../constants');
class MountItems extends IPCContainer {
retryIntervals = {};
activeDetections = [];
state = {
DisplayRetry: false,
RetryItems: {},
};
addMountsBusy = provider => {
this.props.setMountsBusy(true);
this.activeDetections.push(provider);
};
cancelRetryMount = (provider, stateCallback) => {
clearInterval(this.retryIntervals[provider]);
delete this.retryIntervals[provider];
if (stateCallback) {
let retryItems = {
...this.state.RetryItems,
};
delete retryItems[provider];
this.setState({
DisplayRetry: Object.keys(retryItems).length > 0,
RetryItems: retryItems,
}, () => {
if (this.state.DisplayRetry) {
this.sendRequest(Constants.IPC_Show_Window);
}
stateCallback();
});
}
};
componentDidMount() {
this.setRequestHandler(Constants.IPC_Detect_Mount_Reply, this.onDetectMountReply);
this.setRequestHandler(Constants.IPC_Mount_Drive_Reply, this.onMountDriveReply);
this.setRequestHandler(Constants.IPC_Unmount_Drive_Reply, this.onUnmountDriveReply);
this.props.resetMountsState();
this.detectMounts();
}
componentWillUnmount() {
for (const provider in this.state.RetryItems) {
if (this.state.RetryItems.hasOwnProperty(provider)) {
this.cancelRetryMount(provider);
}
}
this.props.resetMountsState();
this.activeDetections = [];
super.componentWillUnmount();
};
detectMount = provider => {
this.addMountsBusy(provider);
this.sendRequest(Constants.IPC_Detect_Mount, {
RemoteMounts: this.props.RemoteMounts,
Provider: provider,
Version: this.props.InstalledVersion,
});
};
detectMounts = ()=> {
if (!this.state.DisplayRetry) {
const providerList = this.getProviderList();
providerList.forEach(provider => {
this.detectMount(provider);
});
}
};
displayRetryMount = (provider, remote, mountLocation, msg) => {
if (!this.state.RetryItems[provider]) {
let retryItems = {
...this.state.RetryItems
};
retryItems[provider] = {
RetrySeconds: 10,
RetryMessage: msg ? msg.toString() : null,
};
const mountState = {
AllowMount: false,
Mounted: false,
};
this.props.setMountState(provider, mountState);
this.setState({
DisplayRetry: true,
RetryItems: retryItems,
}, () => {
this.sendRequest(Constants.IPC_Show_Window);
this.retryIntervals[provider] = setInterval(() => {
let retryItems = {
...this.state.RetryItems,
};
const retrySeconds = retryItems[provider].RetrySeconds - 1;
if (retrySeconds === 0) {
this.cancelRetryMount(provider, () => {
this.handleMountUnMount(provider, remote,true, mountLocation);
});
} else {
retryItems[provider].RetrySeconds = retrySeconds;
this.setState({
RetryItems: retryItems,
});
}
}, 1000);
});
}
};
handleBrowseLocation = (provider, location) => {
location = this.sendSyncRequest(Constants.IPC_Browse_Directory, {
Title: provider + ' Mount Location',
Location: location,
});
if (location && (location.length > 0)) {
this.handleMountLocationChanged(provider, location);
}
};
handleMountLocationChanged = (provider, mountLocation) => {
const state = {
...this.props.ProviderState[provider],
MountLocation: mountLocation,
};
this.props.setProviderState(provider, state);
};
handleMountUnMount = (provider, remote, mount, location) => {
if (!location || (location.trim().length === 0)) {
this.props.notifyError('Mount location is not set');
} else {
let allowAction = true;
if (mount) {
let result = remote ?
{Valid: true, Success: true} :
this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, {
Provider: provider,
Remote: remote,
Version: this.props.InstalledVersion
}).data;
if (result.Success) {
if (result.Valid) {
if (this.props.Platform !== 'win32') {
result = this.sendSyncRequest(Constants.IPC_Check_Mount_Location, {
Location: location,
});
if (!result.Success) {
allowAction = false;
this.props.notifyError(result.Error.toString());
}
}
} else {
allowAction = false;
if ((result.Code === new Uint32Array([-1])[0]) || (result.Code === new Uint8Array([-1])[0])) {
this.displayRetryMount(provider, remote, location, 'Failed to connect to ' + provider + ' daemon');
} else if ((result.Code === new Uint32Array([-3])[0]) || (result.Code === new Uint8Array([-3])[0])) {
this.displayRetryMount(provider, remote, location, 'Incompatible ' + provider + ' daemon. Please upgrade ' + provider + '.');
} else {
this.displayRetryMount(provider, remote, location, 'Version check failed: ' + result.Error);
}
}
} else {
allowAction = false;
if (this.props.Platform === 'win32') {
this.props.notifyError('Failed to launch repertory. Please install Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019.');
} else {
this.displayRetryMount(provider, remote, location, 'Version check failed: ' + result.Error);
}
}
}
if (allowAction) {
this.addMountsBusy(provider);
this.props.setAllowMount(provider, false);
if (mount) {
this.sendRequest(Constants.IPC_Mount_Drive, {
Location: location,
Provider: provider,
Remote: remote,
Version: this.props.InstalledVersion,
});
} else {
this.sendRequest(Constants.IPC_Unmount_Drive, {
Location: location,
Provider: provider,
Remote: remote,
Version: this.props.InstalledVersion,
});
}
}
}
};
getProviderList = () => {
return [
...Constants.PROVIDER_LIST,
...this.props.RemoteMounts,
];
};
hasActiveMount = () => {
for (const provider of Object.keys(this.props.MountState)) {
if (this.props.MountState[provider].Mounted)
return true;
}
return false;
};
onDetectMountReply = (event, arg) => {
const provider = arg.data.Provider;
if (!this.state.RetryItems[provider]) {
if (arg.data.Success && (!arg.data.Active || (arg.data.Location && (arg.data.Location.length > 0)))) {
const mountState = {
AllowMount: true,
DriveLetters: arg.data.DriveLetters,
Mounted: arg.data.Active,
};
this.props.setMountState(provider, mountState);
this.updateMountLocation(provider, arg.data.Location, mountState.Mounted, arg.data.DriveLetters);
this.props.setAutoMountProcessed(provider, true);
this.removeMountsBusy(provider);
} else {
this.detectMount(provider);
this.removeMountsBusy(provider);
}
}
};
onMountDriveReply = (event, arg) => {
this.props.setMounted(arg.data.Provider, arg.data.Success);
this.detectMount(arg.data.Provider);
this.removeMountsBusy(arg.data.Provider);
};
onUnmountDriveReply = (event, arg) => {
if (arg && arg.data && !arg.data.Expected && arg.data.Location && this.props.ProviderState[arg.data.Provider].AutoRestart) {
this.displayRetryMount(arg.data.Provider, arg.data.Remote, arg.data.Location);
} else {
this.detectMount(arg.data.Provider);
}
this.removeMountsBusy(arg.data.Provider);
};
removeMountsBusy = provider => {
const idx = this.activeDetections.indexOf(provider);
if (idx > -1) {
this.activeDetections.splice(idx, 1);
}
this.props.setMountsBusy((this.activeDetections.length > 0) || this.hasActiveMount());
};
updateMountLocation = (provider, location, mounted, driveLetters) => {
const providerState = this.props.ProviderState[provider];
if (location.length === 0) {
location = (this.props.Platform === 'win32') ?
providerState.MountLocation || driveLetters[0] :
providerState.MountLocation;
}
if (location !== providerState.MountLocation) {
const value = (this.props.Platform === 'win32') ?
driveLetters.indexOf(location) :
location;
this.handleMountLocationChanged(provider, value);
}
if (!this.props.AutoMountProcessed[provider] &&
this.props.ProviderState[provider].AutoMount &&
!mounted &&
(location.length > 0)) {
this.handleMountUnMount(provider, this.props.RemoteMounts.includes(provider),true, location);
}
};
render() {
let retryDisplay;
if (this.state.DisplayRetry) {
let retryList = [];
let retryCount = 0;
for (const provider in this.state.RetryItems) {
if (this.state.RetryItems.hasOwnProperty(provider)) {
if (this.state.RetryItems[provider].RetryMessage) {
retryList.push(<p key={'rl_' + retryList.length}>{this.state.RetryItems[provider].RetryMessage}</p>);
}
retryList.push(<Button clicked={() => this.cancelRetryMount(provider, () => this.detectMounts())}
key={'rl_' + retryList.length}>Cancel {provider} Remount
({this.state.RetryItems[provider].RetrySeconds}s)</Button>);
if (++retryCount < Object.keys(this.state.RetryItems).length) {
retryList.push(<div style={{paddingTop: 'var(--default_spacing)'}}
key={'rl_' + retryList.length}/>);
}
}
}
retryDisplay = (
<Modal>
<Box dxDark dxStyle={{padding: 'var(--default_spacing)', minWidth: '70vw'}}>
<h1 style={{textAlign: 'center', paddingBottom: 'var(--default_spacing)', color: 'var(--text_color_error)'}}>Mount Failed</h1>
{retryList}
</Box>
</Modal>
)
}
let footerItems = [];
if (this.props.remoteSupported) {
footerItems.push(<AddRemoteMount key={'hi_' + footerItems.length}/>);
} else {
footerItems.push(<div key={'hi_' + footerItems.length}
style={{height: '27px'}}/>);
}
let items = [];
for (const provider of Constants.PROVIDER_LIST) {
items.push((
<MountItem allowRemove={false}
browseClicked={this.handleBrowseLocation}
changed={e => this.handleMountLocationChanged(provider, e.target.value)}
clicked={this.handleMountUnMount}
key={'it_' + items.length}
provider={provider}/>
));
items.push(<div key={'it_' + items.length}
style={{paddingTop: 'var(--default_spacing)'}} />)
}
if (this.props.remoteSupported) {
for (const provider of this.props.RemoteMounts) {
items.push((
<MountItem allowRemove={true}
browseClicked={this.handleBrowseLocation}
changed={e => this.handleMountLocationChanged(provider, e.target.value)}
clicked={this.handleMountUnMount}
key={'it_' + items.length}
provider={provider}
remote/>
));
items.push(<div key={'it_' + items.length}
style={{paddingTop: 'var(--default_spacing)'}}/>)
}
items.splice(items.length - 1, 1);
} else {
items.splice(items.length - 1, 1)
}
return (
<div style={{margin: 0, padding: 0}}>
{retryDisplay}
<div className={this.props.remoteSupported ? 'MountItemsRemote' : 'MountItems'}>
{items}
</div>
<div style={{paddingTop: 'var(--default_spacing)'}}/>
{footerItems}
</div>);
}
}
const mapStateToProps = state => {
return {
AutoMountProcessed: state.mounts.AutoMountProcessed,
InstalledVersion: state.relver.InstalledVersion,
MountState: state.mounts.MountState,
MountsBusy: state.mounts.MountsBusy,
Platform: state.common.Platform,
ProviderState: state.mounts.ProviderState,
RemoteMounts: state.mounts.RemoteMounts,
}
};
const mapDispatchToProps = dispatch => {
return {
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
resetMountsState: () => dispatch(resetMountsState()),
setAllowMount: (provider, allow) => dispatch(setAllowMount(provider, allow)),
setAutoMountProcessed: (provider, processed) => dispatch(setAutoMountProcessed(provider, processed)),
setMounted: (provider, mounted) => dispatch(setMounted(provider, mounted)),
setMountsBusy: busy => dispatch(setBusy(busy)),
setMountState: (provider, state) => dispatch(setMountState(provider, state)),
setProviderState: (provider, state) => dispatch(setProviderState(provider, state)),
}
};
export default connect(mapStateToProps, mapDispatchToProps)(MountItems);