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

366 lines
12 KiB
JavaScript

import React from 'react';
import AddRemoteMount from '../../components/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 '../../components/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 = {};
state = {
DisplayRetry: false,
RetryItems: {},
};
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_Mounts_Reply, this.onDetectMountsReply);
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();
super.componentWillUnmount();
};
detectMounts = ()=> {
if (!this.state.DisplayRetry) {
this.props.setMountsBusy(true);
this.sendRequest(Constants.IPC_Detect_Mounts, {
Version: this.props.InstalledVersion,
});
}
};
displayRetryMount = (provider, 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, 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, value) => {
const location = (this.props.Platform === 'win32') ?
this.props.MountState[provider].DriveLetters[value] :
value;
const state = {
...this.props.ProviderState[provider],
MountLocation: location,
};
this.props.setProviderState(provider, state);
};
handleMountUnMount = (provider, mount, location) => {
if (!location || (location.trim().length === 0)) {
this.props.notifyError('Mount location is not set');
} else {
let allowAction = true;
if (mount) {
let result = this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, {
Provider: provider,
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, location, 'Failed to connect to ' + provider + ' daemon');
} else if ((result.Code === new Uint32Array([-3])[0]) || (result.Code === new Uint8Array([-3])[0])) {
this.displayRetryMount(provider, location, 'Incompatible ' + provider + ' daemon. Please upgrade ' + provider + '.');
} else {
this.displayRetryMount(provider, 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, location, 'Version check failed: ' + result.Error);
}
}
}
if (allowAction) {
this.props.setMountsBusy(true);
this.props.setAllowMount(provider, false);
if (mount) {
this.sendRequest(Constants.IPC_Mount_Drive, {
Location: location,
NoConsoleSupported: this.props.noConsoleSupported,
Provider: provider,
Version: this.props.InstalledVersion,
});
} else {
this.sendRequest(Constants.IPC_Unmount_Drive, {
Location: location,
Provider: provider,
Version: this.props.InstalledVersion,
});
}
}
}
};
onDetectMountsReply = (event, arg) => {
if (!this.state.DisplayRetry && arg.data.Success) {
let mountsBusy = false;
let mountStates = {};
for (const provider of Constants.PROVIDER_LIST) {
const mountState = {
AllowMount: true,
DriveLetters: (arg.data.DriveLetters[provider]),
Mounted: (arg.data.Locations[provider].length > 0),
};
this.props.setMountState(provider, mountState);
mountsBusy = mountsBusy || mountState.Mounted;
mountStates[provider] = mountState;
}
this.props.setMountsBusy(mountsBusy);
const updateMountLocation = (data, provider) => {
const providerState = this.props.ProviderState[provider];
let location = data.Locations[provider];
if (location.length === 0) {
location = (this.props.Platform === 'win32') ?
providerState.MountLocation || data.DriveLetters[provider][0] :
providerState.MountLocation;
}
if (location !== providerState.MountLocation) {
const value = (this.props.Platform === 'win32') ?
data.DriveLetters[provider].indexOf(location) :
location;
this.handleMountLocationChanged(provider, value);
}
if (!this.props.AutoMountProcessed &&
this.props.ProviderState[provider].AutoMount &&
!mountStates[provider].Mounted &&
(location.length > 0)) {
this.handleMountUnMount(provider, true, location);
}
};
for (const provider of Constants.PROVIDER_LIST) {
updateMountLocation(arg.data, provider);
}
this.props.setAutoMountProcessed(true);
} else {
this.props.notifyError(arg.data.Error);
}
};
onMountDriveReply = (event, arg) => {
this.props.setMounted(arg.data.Provider, arg.data.Success);
this.detectMounts();
};
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.Location);
} else {
this.detectMounts();
}
};
render() {
let retryDisplay;
if (this.state.DisplayRetry) {
let retryList = [];
let retryListCount = 0;
for (const provider in this.state.RetryItems) {
if (this.state.RetryItems.hasOwnProperty(provider)) {
retryListCount++;
if (this.state.RetryItems[provider].RetryMessage) {
retryList.push(<p key={'p' + retryListCount}>{this.state.RetryItems[provider].RetryMessage}</p>);
}
retryList.push(<Button
clicked={()=>this.cancelRetryMount(provider, ()=> this.detectMounts())}
key={'b' + retryListCount}>Cancel {provider} Remount ({this.state.RetryItems[provider].RetrySeconds}s)</Button>);
if (retryListCount < Object.keys(this.state.RetryItems).length) {
retryList.push(<div style={{paddingTop: '8px'}} key={'d' + retryListCount}/>);
}
}
}
retryDisplay = (
<Modal>
<Box dxDark dxStyle={{padding: '8px', minWidth: '70vw'}}>
<h1 style={{textAlign: 'center', paddingBottom: '8px', color: 'var(--text_color_error)'}}>Mount Failed</h1>
{retryList}
</Box>
</Modal>
)
}
let items = [];
for (const provider of Constants.PROVIDER_LIST) {
items.push((
<MountItem allowConfig={this.props.allowConfig}
allowRemove={false}
browseClicked={this.handleBrowseLocation}
changed={e => this.handleMountLocationChanged(provider, e.target.value)}
clicked={this.handleMountUnMount}
key={'mi_' + items.length}
provider={provider}/>
));
items.push(<div key={'di_' + items.length}
style={{paddingTop: '4px'}} />)
}
if (this.props.remoteSupported) {
for (const provider of this.props.RemoteMounts) {
items.push((
<MountItem allowConfig={this.props.allowConfig}
allowRemove={true}
browseClicked={this.handleBrowseLocation}
changed={e => this.handleMountLocationChanged(provider, e.target.value)}
clicked={this.handleMountUnMount}
key={'mi_' + items.length}
provider={provider}/>
));
items.push(<div key={'di_' + items.length}
style={{paddingTop: '4px'}}/>)
}
items.push(<AddRemoteMount key={'mia_' + items.length + 1}/>);
} else {
items.splice(items.length - 1, 1)
}
return (
<div className={'MountItems'}>
{retryDisplay}
{items}
</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: processed => dispatch(setAutoMountProcessed(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);