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
2021-08-04 17:17:16 -05:00

484 lines
14 KiB
JavaScript

import React from 'react';
import './MountItems.css';
import AddMount from '../AddMount/AddMount';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import IPCContainer from '../IPCContainer/IPCContainer';
import Modal from '../../components/UI/Modal/Modal';
import MountItem from './MountItem/MountItem';
import {connect} from 'react-redux';
import {notifyError} from '../../redux/actions/error_actions';
import {
resetMountsState,
setAllowMount,
setAutoMountProcessed,
setBusy,
setMounted,
setMountState,
setProviderState,
} from '../../redux/actions/mount_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() {
Object.keys(this.state.RetryItems).forEach((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,
S3Mounts: this.props.S3Mounts,
Provider: provider,
Version: this.props.InstalledVersion,
});
};
detectMounts = () => {
if (!this.state.DisplayRetry) {
this.getProviderList().forEach((provider) => {
this.detectMount(provider);
});
}
};
displayRetryMount = (provider, remote, s3, 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(() => {
const retryItems = {
...this.state.RetryItems,
};
const retrySeconds = retryItems[provider].RetrySeconds - 1;
if (retrySeconds === 0) {
this.cancelRetryMount(provider, () => {
this.handleMountUnMount(provider, remote, s3, 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, s3, 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 || s3 || provider === 'Skynet'
? {Valid: true, Success: true}
: this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, {
Provider: provider,
Remote: remote,
S3: s3,
Version: this.props.InstalledVersion,
}).data;
const displayRetry = (msg) => {
this.displayRetryMount(provider, remote, s3, location, msg);
};
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]
) {
displayRetry('Failed to connect to ' + provider + ' daemon');
} else if (
result.Code === new Uint32Array([-3])[0] ||
result.Code === new Uint8Array([-3])[0]
) {
displayRetry(
'Incompatible ' + provider + ' daemon. Please upgrade ' + provider + '.'
);
} else {
displayRetry('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 {
displayRetry('Version check failed: ' + result.Error);
}
}
}
if (allowAction) {
this.addMountsBusy(provider);
this.props.setAllowMount(provider, false);
this.sendRequest(mount ? Constants.IPC_Mount_Drive : Constants.IPC_Unmount_Drive, {
Location: location,
Provider: provider,
Remote: remote,
S3: s3,
Version: this.props.InstalledVersion,
});
}
}
};
getProviderList = (providersOnly) => {
const providerList = Constants.PROVIDER_LIST.filter((i) => {
return (
(i === 'Skynet' && this.props.skynetSupported) ||
(i === 'ScPrime' && this.props.scPrimeSupported) ||
(i === 'Sia' && this.props.siaSupported)
);
});
let remoteList = [];
if (this.props.remoteSupported && !providersOnly) {
remoteList = [...this.props.RemoteMounts];
}
let s3List = [];
if (this.props.s3Supported && !providersOnly) {
s3List = [...this.props.S3Mounts];
}
return [...providerList, ...remoteList, ...s3List];
};
hasActiveMount = () => {
return !!Object.keys(this.props.MountState).find((provider) => {
return this.props.MountState[provider].Mounted;
});
};
onDetectMountReply = (_, 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 = (_, arg) => {
this.props.setMounted(arg.data.Provider, arg.data.Success);
this.detectMount(arg.data.Provider);
this.removeMountsBusy(arg.data.Provider);
};
onUnmountDriveReply = (_, 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 || providerState.MountLocation.trim().length === 0
? driveLetters[0]
: providerState.MountLocation
: providerState.MountLocation;
}
if (location !== providerState.MountLocation) {
this.handleMountLocationChanged(provider, location);
}
if (
!this.props.AutoMountProcessed[provider] &&
this.props.ProviderState[provider].AutoMount &&
!mounted &&
location.length > 0
) {
this.handleMountUnMount(
provider,
this.props.RemoteMounts.includes(provider),
this.props.S3Mounts.includes(provider),
true,
location
);
}
};
render() {
let retryDisplay;
if (this.state.DisplayRetry) {
const retryList = [];
let retryCount = 0;
Object.keys(this.state.RetryItems).forEach((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>
);
}
const footerItems = [];
if (this.props.remoteSupported || this.props.s3Supported) {
footerItems.push(
<AddMount
remoteSupported={this.props.remoteSupported}
s3Supported={this.props.s3Supported}
key={'hi_' + footerItems.length}
/>
);
} else {
footerItems.push(<div key={'hi_' + footerItems.length} style={{height: '27px'}}/>);
}
const mountItems = [];
const addMountItem = (provider, remote, s3) => {
if (mountItems.length > 0) {
mountItems.push(
<div
key={'it_' + mountItems.length}
style={{paddingTop: 'calc(var(--default_spacing) * 2.5)'}}
/>
);
}
mountItems.push(
<MountItem
allowRemove={remote || s3}
browseClicked={this.handleBrowseLocation}
changed={(e) => this.handleMountLocationChanged(provider, e.target.value)}
clicked={this.handleMountUnMount}
key={'it_' + mountItems.length}
provider={provider}
remote={remote}
s3={s3}
/>
);
};
this.getProviderList(true).forEach((provider) => addMountItem(provider));
if (this.props.remoteSupported) {
this.props.RemoteMounts.forEach((provider) => addMountItem(provider, true));
}
if (this.props.s3Supported) {
this.props.S3Mounts.forEach((provider) => addMountItem(provider, false, true));
}
return (
<div style={{margin: 0, padding: 0}}>
{retryDisplay}
<div
className={
this.props.remoteSupported || this.props.s3Supported ? 'MountItemsRemote' : 'MountItems'
}>
{mountItems}
</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,
S3Mounts: state.mounts.S3Mounts,
};
};
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);