Prettier support

This commit is contained in:
2021-03-10 21:14:32 -06:00
parent c51b527707
commit 0924490a6f
99 changed files with 5504 additions and 3979 deletions

View File

@@ -1,29 +1,32 @@
import React from 'react';
import {Component} from 'react';
import { Component } from 'react';
import './AddMount.css';
import {connect} from 'react-redux';
import { connect } from 'react-redux';
import Button from '../../components/UI/Button/Button';
import Box from '../../components/UI/Box/Box';
import Text from '../../components/UI/Text/Text';
import {notifyError} from '../../redux/actions/error_actions';
import {addRemoteMount, addS3Mount} from '../../redux/actions/mount_actions';
import {createModalConditionally} from '../../utils';
import { notifyError } from '../../redux/actions/error_actions';
import { addRemoteMount, addS3Mount } from '../../redux/actions/mount_actions';
import { createModalConditionally } from '../../utils.jsx';
import DropDown from '../../components/UI/DropDown/DropDown';
import * as Constants from '../../constants';
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
RemoteMounts: state.mounts.RemoteMounts,
S3Mounts: state.mounts.S3Mounts,
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
addRemoteMount: (hostNameOrIp, port, token) => dispatch(addRemoteMount(hostNameOrIp, port, token)),
addS3Mount: (name, accessKey, secretKey, region, bucketName, url) => dispatch(addS3Mount(name, accessKey, secretKey, region, bucketName, url)),
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
}
addRemoteMount: (hostNameOrIp, port, token) =>
dispatch(addRemoteMount(hostNameOrIp, port, token)),
addS3Mount: (name, accessKey, secretKey, region, bucketName, url) =>
dispatch(addS3Mount(name, accessKey, secretKey, region, bucketName, url)),
notifyError: (msg, critical, callback) =>
dispatch(notifyError(msg, critical, callback)),
};
};
const default_state = {
@@ -40,207 +43,288 @@ const default_state = {
Token: '',
};
export default connect(mapStateToProps, mapDispatchToProps)(class extends Component {
state = {
...default_state,
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(
class extends Component {
state = {
...default_state,
};
addRemoteMount = () => {
if (this.state.HostNameOrIp.length === 0) {
this.props.notifyError('Hostname or IP cannot be empty.');
} else {
const provider = 'Remote' + this.state.HostNameOrIp + ':' + this.state.Port;
if (this.props.RemoteMounts.includes(provider)) {
this.props.notifyError('Remote host already exists');
addRemoteMount = () => {
if (this.state.HostNameOrIp.length === 0) {
this.props.notifyError('Hostname or IP cannot be empty.');
} else {
this.setState({
DisplayRemote: false
}, () => {
this.props.addRemoteMount(this.state.HostNameOrIp, this.state.Port, this.state.Token);
this.setState({
...default_state,
});
});
const provider =
'Remote' + this.state.HostNameOrIp + ':' + this.state.Port;
if (this.props.RemoteMounts.includes(provider)) {
this.props.notifyError('Remote host already exists');
} else {
this.setState(
{
DisplayRemote: false,
},
() => {
this.props.addRemoteMount(
this.state.HostNameOrIp,
this.state.Port,
this.state.Token
);
this.setState({
...default_state,
});
}
);
}
}
}
};
};
addS3Mount = () => {
if (this.state.Name.length === 0) {
this.props.notifyError('Name cannot be empty.');
} else if (this.state.AccessKey.length === 0) {
this.props.notifyError('AccessKey cannot be empty.');
} else if (this.state.SecretKey.length === 0) {
this.props.notifyError('SecretKey cannot be empty.')
} else {
const provider = 'S3' + this.state.Name;
if (this.props.S3Mounts.includes(provider)) {
this.props.notifyError('Remote host already exists');
addS3Mount = () => {
if (this.state.Name.length === 0) {
this.props.notifyError('Name cannot be empty.');
} else if (this.state.AccessKey.length === 0) {
this.props.notifyError('AccessKey cannot be empty.');
} else if (this.state.SecretKey.length === 0) {
this.props.notifyError('SecretKey cannot be empty.');
} else {
this.setState({
DisplayS3: false
}, () => {
this.props.addS3Mount(this.state.Name, this.state.AccessKey, this.state.SecretKey,
this.state.Region, this.state.BucketName, Constants.S3_PROVIDER_URL[this.state.Provider]);
this.setState({
...default_state,
});
});
const provider = 'S3' + this.state.Name;
if (this.props.S3Mounts.includes(provider)) {
this.props.notifyError('Remote host already exists');
} else {
this.setState(
{
DisplayS3: false,
},
() => {
this.props.addS3Mount(
this.state.Name,
this.state.AccessKey,
this.state.SecretKey,
this.state.Region,
this.state.BucketName,
Constants.S3_PROVIDER_URL[this.state.Provider]
);
this.setState({
...default_state,
});
}
);
}
}
};
handleAddS3Mount = () => {
this.setState({
DisplayRemote: false,
DisplayS3: true,
});
};
handleAddRemoteMount = () => {
this.setState({
DisplayRemote: true,
DisplayS3: false,
});
};
render() {
const displayAddRemote = createModalConditionally(
this.state.DisplayRemote,
<Box
dxDark
dxStyle={{
width: 'auto',
height: 'auto',
padding: 'var(--default_spacing)',
}}
>
<h1
style={{
textAlign: 'center',
paddingBottom: 'var(--default_spacing)',
}}
>
Add Remote Mount
</h1>
<Text text={'Hostname or IP'} textAlign={'left'} type={'Heading2'} />
<input
onChange={(e) =>
this.setState({ HostNameOrIp: e.target.value.trim() })
}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.HostNameOrIp}
/>
<div style={{ paddingTop: 'var(--default_spacing)' }} />
<Text text={'Port'} textAlign={'left'} type={'Heading2'} />
<input
max={65535}
min={1025}
onChange={(e) => this.setState({ Port: e.target.value })}
className={'ConfigurationItemInput'}
type={'number'}
value={this.state.Port}
/>
<div style={{ paddingTop: 'var(--default_spacing)' }} />
<Text text={'Remote Token'} textAlign={'left'} type={'Heading2'} />
<input
onChange={(e) => this.setState({ Token: e.target.value })}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.Token}
/>
<div style={{ paddingTop: 'var(--default_spacing)' }} />
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Button
buttonStyles={{ width: '100%' }}
clicked={() => this.addRemoteMount()}
>
OK
</Button>
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<Button
buttonStyles={{ width: '100%' }}
clicked={() => this.setState({ DisplayRemote: false })}
>
Cancel
</Button>
</div>
</Box>
);
const displayAddS3 = createModalConditionally(
this.state.DisplayS3,
<Box
dxDark
dxStyle={{
width: 'auto',
height: 'auto',
padding: 'var(--default_spacing)',
}}
>
<h1
style={{
textAlign: 'center',
paddingBottom: 'var(--default_spacing)',
}}
>
Add S3 Mount
</h1>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Text text={'Name'} textAlign={'left'} type={'Heading2'} />
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<Text text={'Provider'} textAlign={'left'} type={'Heading2'} />
</div>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<input
onChange={(e) => this.setState({ Name: e.target.value.trim() })}
className={'ConfigurationItemInput'}
style={{ width: '100%' }}
type={'text'}
value={this.state.Name}
/>
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<DropDown
changed={(e) => this.setState({ Provider: e.target.value })}
items={Constants.S3_PROVIDER_LIST}
selected={this.state.Provider}
/>
</div>
<div style={{ paddingTop: 'var(--default_spacing)' }} />
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Text
text={'Bucket Name (optional)'}
textAlign={'left'}
type={'Heading2'}
/>
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<Text text={'Region'} textAlign={'left'} type={'Heading2'} />
</div>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<input
onChange={(e) => this.setState({ BucketName: e.target.value })}
className={'ConfigurationItemInput'}
style={{ width: '100%' }}
type={'text'}
value={this.state.BucketName}
/>
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<input
onChange={(e) => this.setState({ Region: e.target.value })}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.Region}
/>
</div>
<div style={{ paddingTop: 'var(--default_spacing)' }} />
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Text text={'Access Key'} textAlign={'left'} type={'Heading2'} />
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<Text text={'Secret Key'} textAlign={'left'} type={'Heading2'} />
</div>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<input
onChange={(e) => this.setState({ AccessKey: e.target.value })}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.AccessKey}
/>
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<input
onChange={(e) => this.setState({ SecretKey: e.target.value })}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.SecretKey}
/>
</div>
<div style={{ paddingTop: 'calc(var(--default_spacing) * 2)' }} />
<div style={{ display: 'flex', flexDirection: 'row' }}>
<div style={{ width: '200%' }} />
<Button
buttonStyles={{ width: '100%' }}
clicked={() => this.addS3Mount()}
>
OK
</Button>
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
<Button
buttonStyles={{ width: '100%' }}
clicked={() => this.setState({ DisplayS3: false })}
>
Cancel
</Button>
</div>
</Box>
);
return (
<div className={'AddMount'}>
{displayAddRemote}
{displayAddS3}
<div className={'AddMountButtons'}>
{this.props.remoteSupported ? (
<Button
className={'AddMountButton'}
clicked={this.handleAddRemoteMount}
>
Add Remote Mount
</Button>
) : null}
{this.props.remoteSupported && this.props.s3Supported ? (
<div style={{ paddingRight: 'var(--default_spacing)' }} />
) : null}
{this.props.s3Supported ? (
<Button
className={'AddMountButton'}
clicked={this.handleAddS3Mount}
>
Add S3 Mount
</Button>
) : null}
</div>
</div>
);
}
};
handleAddS3Mount = () => {
this.setState({
DisplayRemote: false,
DisplayS3: true,
});
};
handleAddRemoteMount = () => {
this.setState({
DisplayRemote: true,
DisplayS3: false,
});
};
render() {
const displayAddRemote = createModalConditionally(this.state.DisplayRemote, (
<Box dxDark
dxStyle={{width: 'auto', height: 'auto', padding: 'var(--default_spacing)'}}>
<h1 style={{textAlign: 'center', paddingBottom: 'var(--default_spacing)'}}>Add Remote
Mount</h1>
<Text text={'Hostname or IP'}
textAlign={'left'}
type={'Heading2'}/>
<input onChange={e => this.setState({HostNameOrIp: e.target.value.trim()})}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.HostNameOrIp}/>
<div style={{paddingTop: 'var(--default_spacing)'}}/>
<Text text={'Port'}
textAlign={'left'}
type={'Heading2'}/>
<input max={65535}
min={1025}
onChange={e => this.setState({Port: e.target.value})}
className={'ConfigurationItemInput'}
type={'number'}
value={this.state.Port}/>
<div style={{paddingTop: 'var(--default_spacing)'}}/>
<Text text={'Remote Token'}
textAlign={'left'}
type={'Heading2'}/>
<input onChange={e => this.setState({Token: e.target.value})}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.Token}/>
<div style={{paddingTop: 'var(--default_spacing)'}}/>
<div style={{display: 'flex', flexDirection: 'row'}}>
<Button buttonStyles={{width: '100%'}}
clicked={() => this.addRemoteMount()}>OK</Button>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<Button buttonStyles={{width: '100%'}}
clicked={() => this.setState({DisplayRemote: false})}>Cancel</Button>
</div>
</Box>
));
const displayAddS3 = createModalConditionally(this.state.DisplayS3, (
<Box dxDark
dxStyle={{width: 'auto', height: 'auto', padding: 'var(--default_spacing)'}}>
<h1 style={{textAlign: 'center', paddingBottom: 'var(--default_spacing)'}}>Add S3
Mount</h1>
<div style={{display: 'flex', flexDirection: 'row'}}>
<Text text={'Name'}
textAlign={'left'}
type={'Heading2'}/>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<Text text={'Provider'}
textAlign={'left'}
type={'Heading2'}/>
</div>
<div style={{display: 'flex', flexDirection: 'row'}}>
<input onChange={e => this.setState({Name: e.target.value.trim()})}
className={'ConfigurationItemInput'}
style={{width: '100%'}}
type={'text'}
value={this.state.Name}/>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<DropDown changed={e => this.setState({Provider: e.target.value})}
items={Constants.S3_PROVIDER_LIST}
selected={this.state.Provider}/>
</div>
<div style={{paddingTop: 'var(--default_spacing)'}}/>
<div style={{display: 'flex', flexDirection: 'row'}}>
<Text text={'Bucket Name (optional)'}
textAlign={'left'}
type={'Heading2'}/>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<Text text={'Region'}
textAlign={'left'}
type={'Heading2'}/>
</div>
<div style={{display: 'flex', flexDirection: 'row'}}>
<input onChange={e => this.setState({BucketName: e.target.value})}
className={'ConfigurationItemInput'}
style={{width: '100%'}}
type={'text'}
value={this.state.BucketName}/>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<input onChange={e => this.setState({Region: e.target.value})}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.Region}/>
</div>
<div style={{paddingTop: 'var(--default_spacing)'}}/>
<div style={{display: 'flex', flexDirection: 'row'}}>
<Text text={'Access Key'}
textAlign={'left'}
type={'Heading2'}/>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<Text text={'Secret Key'}
textAlign={'left'}
type={'Heading2'}/>
</div>
<div style={{display: 'flex', flexDirection: 'row'}}>
<input onChange={e => this.setState({AccessKey: e.target.value})}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.AccessKey}/>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<input onChange={e => this.setState({SecretKey: e.target.value})}
className={'ConfigurationItemInput'}
type={'text'}
value={this.state.SecretKey}/>
</div>
<div style={{paddingTop: 'calc(var(--default_spacing) * 2)'}}/>
<div style={{display: 'flex', flexDirection: 'row'}}>
<div style={{width: '200%'}}/>
<Button buttonStyles={{width: '100%'}}
clicked={() => this.addS3Mount()}>OK</Button>
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
<Button buttonStyles={{width: '100%'}}
clicked={() => this.setState({DisplayS3: false})}>Cancel</Button>
</div>
</Box>
));
return (
<div className={'AddMount'}>
{displayAddRemote}
{displayAddS3}
<div className={'AddMountButtons'}>
{this.props.remoteSupported ?
<Button className={'AddMountButton'}
clicked={this.handleAddRemoteMount}>Add Remote Mount</Button> : null}
{this.props.remoteSupported && this.props.s3Supported ?
<div style={{paddingRight: 'var(--default_spacing)'}}/> : null}
{this.props.s3Supported ?
<Button className={'AddMountButton'}
clicked={this.handleAddS3Mount}>Add S3 Mount</Button> : null}
</div>
</div>
);
}
});
);

View File

@@ -1,14 +1,14 @@
import React from 'react';
import './Configuration.css';
import {connect} from 'react-redux';
import { connect } from 'react-redux';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import ConfigurationItem from './ConfigurationItem/ConfigurationItem';
import Modal from '../../components/UI/Modal/Modal';
import IPCContainer from '../IPCContainer/IPCContainer';
import {displayConfiguration} from '../../redux/actions/mount_actions';
import {notifyError} from '../../redux/actions/error_actions';
import {displayPinnedManager} from '../../redux/actions/pinned_manager_actions';
import { displayConfiguration } from '../../redux/actions/mount_actions';
import { notifyError } from '../../redux/actions/error_actions';
import { displayPinnedManager } from '../../redux/actions/pinned_manager_actions';
const Constants = require('../../constants');
@@ -25,7 +25,7 @@ class Configuration extends IPCContainer {
ItemList: [],
Saving: false,
ShowAdvanced: false,
Template: {}
Template: {},
};
checkItemChanged = (itemA, itemB) => {
@@ -33,7 +33,7 @@ class Configuration extends IPCContainer {
if (itemA.value.length !== itemB.value.length) {
return true;
}
return itemA.value.filter(i => !itemB.value.includes(i)).length !== 0;
return itemA.value.filter((i) => !itemB.value.includes(i)).length !== 0;
}
return itemA.value !== itemB.value;
};
@@ -52,7 +52,9 @@ class Configuration extends IPCContainer {
const changedObjectItems = [];
let j = 0;
for (const item of this.state.ObjectLookup[key]) {
if (this.checkItemChanged(this.state.OriginalObjectLookup[key][j++], item)) {
if (
this.checkItemChanged(this.state.OriginalObjectLookup[key][j++], item)
) {
changedObjectItems.push(item);
}
}
@@ -65,7 +67,7 @@ class Configuration extends IPCContainer {
}
}
if ((changedItems.length > 0) || changedObjectLookup) {
if (changedItems.length > 0 || changedObjectLookup) {
this.setState({
ChangedItems: changedItems,
ChangedObjectLookup: changedObjectLookup,
@@ -77,9 +79,18 @@ class Configuration extends IPCContainer {
componentDidMount() {
this._isMounted = true;
this.setRequestHandler(Constants.IPC_Get_Config_Template_Reply, this.onGetConfigTemplateReply);
this.setRequestHandler(Constants.IPC_Get_Config_Reply, this.onGetConfigReply);
this.setRequestHandler(Constants.IPC_Set_Config_Values_Reply, this.onSetConfigValuesReply);
this.setRequestHandler(
Constants.IPC_Get_Config_Template_Reply,
this.onGetConfigTemplateReply
);
this.setRequestHandler(
Constants.IPC_Get_Config_Reply,
this.onGetConfigReply
);
this.setRequestHandler(
Constants.IPC_Set_Config_Values_Reply,
this.onSetConfigValuesReply
);
this.sendRequest(Constants.IPC_Get_Config_Template, {
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
@@ -95,55 +106,57 @@ class Configuration extends IPCContainer {
createItemList = (config, template) => {
const objectList = [];
const itemList = Object
.keys(config)
.map(key => {
return {
advanced: template[key] ? template[key].advanced : false,
hide_remote: template[key] ? template[key].hide_remote : false,
label: key,
remote: template[key] ? template[key].remote : false,
type: template[key] ? template[key].type : null,
value: (template[key] && (template[key].type === 'object')) ?
config[key] :
(template[key] && (template[key].type === 'string_array')) ?
config[key] :
config[key].toString(),
};
})
.filter(i => {
let ret = template[i.label];
if (ret && (template[i.label].type === 'object')) {
objectList.push(i);
ret = false;
}
return ret;
});
const itemList = Object.keys(config)
.map((key) => {
return {
advanced: template[key] ? template[key].advanced : false,
hide_remote: template[key] ? template[key].hide_remote : false,
label: key,
remote: template[key] ? template[key].remote : false,
type: template[key] ? template[key].type : null,
value:
template[key] && template[key].type === 'object'
? config[key]
: template[key] && template[key].type === 'string_array'
? config[key]
: config[key].toString(),
};
})
.filter((i) => {
let ret = template[i.label];
if (ret && template[i.label].type === 'object') {
objectList.push(i);
ret = false;
}
return ret;
});
return {
ObjectList: objectList,
ItemList: itemList,
}
};
};
handleItemChanged = (target, idx) => {
const itemList = [
...this.state.ItemList
];
itemList[idx].value = target.type === 'textarea' ? target.string_array : target.value.toString();
const itemList = [...this.state.ItemList];
itemList[idx].value =
target.type === 'textarea'
? target.string_array
: target.value.toString();
this.setState({
ItemList: itemList
ItemList: itemList,
});
};
handleObjectItemChanged = (target, name, idx) => {
const itemList = [
...this.state.ObjectLookup[name]
];
const itemList = [...this.state.ObjectLookup[name]];
const objectLookup = {
...this.state.ObjectLookup,
};
itemList[idx].value = target.type === 'textarea' ? target.string_array : target.value.toString();
itemList[idx].value =
target.type === 'textarea'
? target.string_array
: target.value.toString();
objectLookup[name] = itemList;
this.setState({
ObjectLookup: objectLookup,
@@ -157,12 +170,19 @@ class Configuration extends IPCContainer {
let objectLookup = {};
for (const obj of list.ObjectList) {
const list2 = this.createItemList(obj.value, this.state.Template[obj.label].template);
const list2 = this.createItemList(
obj.value,
this.state.Template[obj.label].template
);
objectLookup[obj.label] = list2.ItemList;
}
const isRemoteMount = this.props.remoteSupported &&
JSON.parse(objectLookup['RemoteMount'].find(s => s.label === 'IsRemoteMount').value);
const isRemoteMount =
this.props.remoteSupported &&
JSON.parse(
objectLookup['RemoteMount'].find((s) => s.label === 'IsRemoteMount')
.value
);
if (isRemoteMount) {
for (const obj of list.ObjectList) {
if (obj.hide_remote) {
@@ -172,15 +192,16 @@ class Configuration extends IPCContainer {
}
const objectLookupCopy = JSON.parse(JSON.stringify(objectLookup));
this.setState({
IsRemoteMount: isRemoteMount,
ItemList: list.ItemList,
ObjectLookup: objectLookup,
OriginalItemList: itemListCopy,
OriginalObjectLookup: objectLookupCopy,
}, () => {
});
this.setState(
{
IsRemoteMount: isRemoteMount,
ItemList: list.ItemList,
ObjectLookup: objectLookup,
OriginalItemList: itemListCopy,
OriginalObjectLookup: objectLookupCopy,
},
() => {}
);
} else {
this.props.notifyError(arg.data.Error);
}
@@ -188,16 +209,19 @@ class Configuration extends IPCContainer {
onGetConfigTemplateReply = (event, arg) => {
if (arg.data.Success) {
this.setState({
Template: arg.data.Template,
}, () => {
this.sendRequest(Constants.IPC_Get_Config, {
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
});
});
this.setState(
{
Template: arg.data.Template,
},
() => {
this.sendRequest(Constants.IPC_Get_Config, {
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
});
}
);
} else {
this.props.notifyError(arg.data.Error, false, () => {
if (this._isMounted) {
@@ -212,77 +236,102 @@ class Configuration extends IPCContainer {
};
saveAndClose = () => {
this.setState({
Saving: true,
}, () => {
const changedItems = [];
for (const item of this.state.ChangedItems) {
changedItems.push({
Name: item.label,
Value: item.type === 'string_array' ?
item.value.join(';') :
item.value,
});
}
this.setState(
{
Saving: true,
},
() => {
const changedItems = [];
for (const item of this.state.ChangedItems) {
changedItems.push({
Name: item.label,
Value:
item.type === 'string_array' ? item.value.join(';') : item.value,
});
}
if (this.state.ChangedObjectLookup) {
for (const key of Object.keys(this.state.ChangedObjectLookup)) {
for (const item of this.state.ChangedObjectLookup[key]) {
changedItems.push({
Name: key + '.' + item.label,
Value: item.type === 'string_array' ?
item.value.join(';') :
item.value,
});
if (this.state.ChangedObjectLookup) {
for (const key of Object.keys(this.state.ChangedObjectLookup)) {
for (const item of this.state.ChangedObjectLookup[key]) {
changedItems.push({
Name: key + '.' + item.label,
Value:
item.type === 'string_array'
? item.value.join(';')
: item.value,
});
}
}
}
}
this.sendRequest(Constants.IPC_Set_Config_Values, {
Items: changedItems,
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
});
});
this.sendRequest(Constants.IPC_Set_Config_Values, {
Items: changedItems,
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
});
}
);
};
showRemoteConfigItem = (item, itemList) => {
if (item.advanced &&
if (
item.advanced &&
item.remote &&
this.props.remoteSupported &&
(item.label !== 'IsRemoteMount')) {
const isRemoteMount = JSON.parse(itemList.find(s => s.label === 'IsRemoteMount').value);
const enableRemoteMount = !isRemoteMount &&
JSON.parse(itemList.find(s => s.label === 'EnableRemoteMount').value);
return (item.label === 'RemoteHostNameOrIp') || (item.label === 'RemoteMaxConnections') ?
isRemoteMount :
(item.label === 'RemoteReceiveTimeoutSeconds') || (item.label === 'RemoteSendTimeoutSeconds') || (item.label === 'RemotePort') || (item.label === 'RemoteToken') ?
isRemoteMount || enableRemoteMount :
(item.label === 'EnableRemoteMount') ?
!isRemoteMount :
enableRemoteMount;
item.label !== 'IsRemoteMount'
) {
const isRemoteMount = JSON.parse(
itemList.find((s) => s.label === 'IsRemoteMount').value
);
const enableRemoteMount =
!isRemoteMount &&
JSON.parse(itemList.find((s) => s.label === 'EnableRemoteMount').value);
return item.label === 'RemoteHostNameOrIp' ||
item.label === 'RemoteMaxConnections'
? isRemoteMount
: item.label === 'RemoteReceiveTimeoutSeconds' ||
item.label === 'RemoteSendTimeoutSeconds' ||
item.label === 'RemotePort' ||
item.label === 'RemoteToken'
? isRemoteMount || enableRemoteMount
: item.label === 'EnableRemoteMount'
? !isRemoteMount
: enableRemoteMount;
}
return false;
};
render() {
let confirmSave = null;
if ((this.state.ChangedItems.length > 0) || this.state.ChangedObjectLookup) {
if (this.state.ChangedItems.length > 0 || this.state.ChangedObjectLookup) {
confirmSave = (
<Modal>
<Box dxStyle={{width: '40vw', padding: 'var(--default_spacing)'}}>
<h1 style={{width: '100%', textAlign: 'center'}}>Save Changes?</h1>
<table width='100%'>
<Box dxStyle={{ width: '40vw', padding: 'var(--default_spacing)' }}>
<h1 style={{ width: '100%', textAlign: 'center' }}>
Save Changes?
</h1>
<table width="100%">
<tbody>
<tr>
<td align='center' width='50%'><Button clicked={this.saveAndClose}
disabled={this.state.Saving}>Yes</Button>
</td>
<td align='center' width='50%'><Button clicked={this.props.hideConfiguration}
disabled={this.state.Saving}>No</Button></td>
</tr>
<tr>
<td align="center" width="50%">
<Button
clicked={this.saveAndClose}
disabled={this.state.Saving}
>
Yes
</Button>
</td>
<td align="center" width="50%">
<Button
clicked={this.props.hideConfiguration}
disabled={this.state.Saving}
>
No
</Button>
</td>
</tr>
</tbody>
</table>
</Box>
@@ -294,84 +343,105 @@ class Configuration extends IPCContainer {
let objectItems = [];
for (const key of Object.keys(this.state.ObjectLookup)) {
objectItems.push((
objectItems.push(
<div key={key}>
<h2>{key}</h2>
<div>
{
this.state.ObjectLookup[key].map((k, i) => {
const shouldFocus = autoFocus;
autoFocus = false;
return (
(!k.advanced || (this.state.ShowAdvanced && k.advanced && !k.remote) || this.showRemoteConfigItem(k, this.state.ObjectLookup[key])) ?
<ConfigurationItem advanced={k.advanced}
autoFocus={shouldFocus}
changed={e => this.handleObjectItemChanged(e, key, i)}
grouping={key}
items={this.state.Template[key].template[k.label].items}
key={i}
label={k.label}
readOnly={this.state.IsRemoteMount && ((k.label === 'RemoteHostNameOrIp') || (k.label === 'RemotePort'))}
template={this.state.Template[key].template[k.label]}
value={k.value}/> :
null)
})
}
{this.state.ObjectLookup[key].map((k, i) => {
const shouldFocus = autoFocus;
autoFocus = false;
return !k.advanced ||
(this.state.ShowAdvanced && k.advanced && !k.remote) ||
this.showRemoteConfigItem(k, this.state.ObjectLookup[key]) ? (
<ConfigurationItem
advanced={k.advanced}
autoFocus={shouldFocus}
changed={(e) => this.handleObjectItemChanged(e, key, i)}
grouping={key}
items={this.state.Template[key].template[k.label].items}
key={i}
label={k.label}
readOnly={
this.state.IsRemoteMount &&
(k.label === 'RemoteHostNameOrIp' ||
k.label === 'RemotePort')
}
template={this.state.Template[key].template[k.label]}
value={k.value}
/>
) : null;
})}
</div>
</div>
));
);
}
const configurationItems = this.state.ItemList
.map((k, i) => {
const configurationItems = this.state.ItemList.map((k, i) => {
const shouldFocus = autoFocus;
autoFocus = false;
return (
((!this.state.IsRemoteMount || !k.hide_remote) && (!k.advanced || (this.state.ShowAdvanced && k.advanced))) ?
<ConfigurationItem advanced={k.advanced}
autoFocus={shouldFocus}
changed={e => this.handleItemChanged(e, i)}
grouping={'Settings'}
items={this.state.Template[k.label].items}
key={i}
label={k.label}
template={this.state.Template[k.label]}
value={k.value}/> :
null
);
return (!this.state.IsRemoteMount || !k.hide_remote) &&
(!k.advanced || (this.state.ShowAdvanced && k.advanced)) ? (
<ConfigurationItem
advanced={k.advanced}
autoFocus={shouldFocus}
changed={(e) => this.handleItemChanged(e, i)}
grouping={'Settings'}
items={this.state.Template[k.label].items}
key={i}
label={k.label}
template={this.state.Template[k.label]}
value={k.value}
/>
) : null;
});
return (
<div className={'Configuration'}>
{confirmSave}
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
<div style={{
float: 'right',
margin: 0,
padding: 0,
marginTop: '-4px',
boxSizing: 'border-box',
display: 'block'
}}>
<a href={'#'}
onClick={this.checkSaveRequired}
style={{cursor: 'pointer'}}>X</a>
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
<div
style={{
float: 'right',
margin: 0,
padding: 0,
marginTop: '-4px',
boxSizing: 'border-box',
display: 'block',
}}
>
<a
href={'#'}
onClick={this.checkSaveRequired}
style={{ cursor: 'pointer' }}
>
X
</a>
</div>
<h1 style={{width: '100%', textAlign: 'center'}}>{(
this.props.DisplayRemoteConfiguration ?
this.props.DisplayConfiguration.substr(6) :
this.props.DisplayConfiguration) + ' Configuration '}
<h1 style={{ width: '100%', textAlign: 'center' }}>
{(this.props.DisplayRemoteConfiguration
? this.props.DisplayConfiguration.substr(6)
: this.props.DisplayConfiguration) + ' Configuration '}
</h1>
<div style={{overflowY: 'auto', height: '90%'}}>
{this.props.MState.Mounted && (configurationItems.length > 0) ? <Button
buttonStyles={{width: 'auto', height: 'auto', marginLeft: 'auto', marginRight: '4px'}}
clicked={() => {
this.props.displayPinnedManager(true);
return false;
}}>&nbsp;Pinned File Manager...&nbsp;</Button> : null}
<div style={{marginBottom: '4px'}}/>
<div style={{ overflowY: 'auto', height: '90%' }}>
{this.props.MState.Mounted && configurationItems.length > 0 ? (
<Button
buttonStyles={{
width: 'auto',
height: 'auto',
marginLeft: 'auto',
marginRight: '4px',
}}
clicked={() => {
this.props.displayPinnedManager(true);
return false;
}}
>
&nbsp;Pinned File Manager...&nbsp;
</Button>
) : null}
<div style={{ marginBottom: '4px' }} />
{objectItems}
{(configurationItems.length > 0) ? <h2>Settings</h2> : null}
{configurationItems.length > 0 ? <h2>Settings</h2> : null}
{configurationItems}
</div>
</Box>
@@ -380,22 +450,23 @@ class Configuration extends IPCContainer {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
DisplayConfiguration: state.mounts.DisplayConfiguration,
DisplayRemoteConfiguration: state.mounts.DisplayRemoteConfiguration,
DisplayS3Configuration: state.mounts.DisplayS3Configuration,
MState: state.mounts.MountState[state.mounts.DisplayConfiguration],
Platform: state.common.Platform,
}
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
displayPinnedManager: display => dispatch(displayPinnedManager(display)),
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
displayPinnedManager: (display) => dispatch(displayPinnedManager(display)),
notifyError: (msg, critical, callback) =>
dispatch(notifyError(msg, critical, callback)),
hideConfiguration: () => dispatch(displayConfiguration(null, false)),
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Configuration);

View File

@@ -29,7 +29,7 @@ textarea.ConfigurationItemInput {
box-sizing: border-box;
resize: none;
overflow-y: scroll;
overflow:-moz-scrollbars-horizontal;
overflow: -moz-scrollbars-horizontal;
white-space: nowrap;
}

View File

@@ -1,31 +1,33 @@
import React from 'react';
import './ConfigurationItem.css';
import CheckBox from '../../../components/UI/CheckBox/CheckBox';
import {connect} from 'react-redux';
import {faInfoCircle} from '@fortawesome/free-solid-svg-icons';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {
notifyError,
notifyInfo
} from '../../../redux/actions/error_actions';
import { connect } from 'react-redux';
import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { notifyError, notifyInfo } from '../../../redux/actions/error_actions';
import settings from '../../../assets/settings';
import DropDown from '../../../components/UI/DropDown/DropDown';
import Password from '../../../containers/UI/Password/Password';
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
notifyError: msg => dispatch(notifyError(msg)),
notifyError: (msg) => dispatch(notifyError(msg)),
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
}
};
};
export default connect(null, mapDispatchToProps)(props => {
export default connect(
null,
mapDispatchToProps
)((props) => {
const handleChanged = (e) => {
const target = e.target;
if (target.type === 'checkbox') {
target.value = e.target.checked ? 'true' : 'false';
} else if (target.type === 'textarea') {
e.target.string_array = String(e.target.value).replace(/\r\n/g,'\n').split('\n');
e.target.string_array = String(e.target.value)
.replace(/\r\n/g, '\n')
.split('\n');
}
props.changed(target);
};
@@ -37,137 +39,186 @@ export default connect(null, mapDispatchToProps)(props => {
props.notifyInfo(props.label, description);
};
infoDisplay = <a href={'#'}
className={'ConfigurationInfo'}
onClick={()=>{displayInfo(); return false;}}><FontAwesomeIcon icon={faInfoCircle}/></a>;
infoDisplay = (
<a
href={'#'}
className={'ConfigurationInfo'}
onClick={() => {
displayInfo();
return false;
}}
>
<FontAwesomeIcon icon={faInfoCircle} />
</a>
);
}
let data;
switch (props.template.type) {
case 'bool':
data = <CheckBox changed={handleChanged}
checked={props.value}
disabled={props.readOnly}
autoFocus={props.autoFocus}/>;
break;
data = (
<CheckBox
changed={handleChanged}
checked={props.value}
disabled={props.readOnly}
autoFocus={props.autoFocus}
/>
);
break;
case 'double':
data = <input min={0.0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={e=>handleChanged(e)}
step={'0.01'}
className={'ConfigurationItemInput'}
type={'number'}
value={parseFloat(props.value).toFixed(2)}/>;
break;
data = (
<input
min={0.0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={(e) => handleChanged(e)}
step={'0.01'}
className={'ConfigurationItemInput'}
type={'number'}
value={parseFloat(props.value).toFixed(2)}
/>
);
break;
case 'list':
data = <DropDown alt
auto
autoFocus={props.autoFocus}
changed={handleChanged}
disabled={props.readOnly}
items={props.items}
selected={props.value} />;
break;
data = (
<DropDown
alt
auto
autoFocus={props.autoFocus}
changed={handleChanged}
disabled={props.readOnly}
items={props.items}
selected={props.value}
/>
);
break;
case 'string':
if (props.template.subtype === 'password') {
data = (
<Password autoFocus={props.autoFocus}
changed={s => handleChanged({
target: {
type: 'password',
value: s,
},
})}
disabled={props.readOnly}
mismatchHandler={() => props.notifyError('Passwords do not match')}
value={props.value} />
<Password
autoFocus={props.autoFocus}
changed={(s) =>
handleChanged({
target: {
type: 'password',
value: s,
},
})
}
disabled={props.readOnly}
mismatchHandler={() => props.notifyError('Passwords do not match')}
value={props.value}
/>
);
} else {
data = (
<input onChange={e => handleChanged(e)}
autoFocus={props.autoFocus}
className={'ConfigurationItemInput'}
disabled={props.readOnly}
type={'text'}
value={props.value}/>
data = (
<input
onChange={(e) => handleChanged(e)}
autoFocus={props.autoFocus}
className={'ConfigurationItemInput'}
disabled={props.readOnly}
type={'text'}
value={props.value}
/>
);
}
break;
break;
case 'uint8':
data = <input max={255}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={e=>handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}/>;
break;
data = (
<input
max={255}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={(e) => handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}
/>
);
break;
case 'uint16':
data = <input max={65535}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={e=>handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}/>;
break;
data = (
<input
max={65535}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={(e) => handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}
/>
);
break;
case 'uint32':
data = <input max={4294967295}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={e=>handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}/>;
break;
data = (
<input
max={4294967295}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={(e) => handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}
/>
);
break;
case 'uint64':
data = <input max={18446744073709551615}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={e=>handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}/>;
break;
data = (
<input
max={18446744073709551615}
min={0}
autoFocus={props.autoFocus}
disabled={props.readOnly}
onChange={(e) => handleChanged(e)}
className={'ConfigurationItemInput'}
type={'number'}
value={props.value}
/>
);
break;
case 'string_array':
data = (
<textarea autoFocus={props.autoFocus}
disabled={props.readOnly}
rows={4}
cols={36}
onChange={e=>handleChanged(e)}
className={'ConfigurationItemInput'}
value={props.value.join('\n')} />
<textarea
autoFocus={props.autoFocus}
disabled={props.readOnly}
rows={4}
cols={36}
onChange={(e) => handleChanged(e)}
className={'ConfigurationItemInput'}
value={props.value.join('\n')}
/>
);
break;
break;
case 'password':
data = (
<Password autoFocus={props.autoFocus}
changed={s => handleChanged({
target: {
type: 'password',
value: s,
},
})}
disabled={props.readOnly}
mismatchHandler={() => props.notifyError('Passwords do not match')}
value={props.value} />
<Password
autoFocus={props.autoFocus}
changed={(s) =>
handleChanged({
target: {
type: 'password',
value: s,
},
})
}
disabled={props.readOnly}
mismatchHandler={() => props.notifyError('Passwords do not match')}
value={props.value}
/>
);
break;
break;
default:
data = <div>{props.value}</div>;
@@ -175,13 +226,18 @@ export default connect(null, mapDispatchToProps)(props => {
return (
<div className={'ConfigurationItem'}>
<table cellPadding='2'
width='100%'>
<table cellPadding="2" width="100%">
<tbody>
<tr>
{infoDisplay ?
<td width='100%' valign={'top'}>{infoDisplay} {props.label}</td> :
<td width='100%' valign={'top'}>{props.label}</td>}
{infoDisplay ? (
<td width="100%" valign={'top'}>
{infoDisplay} {props.label}
</td>
) : (
<td width="100%" valign={'top'}>
{props.label}
</td>
)}
<td>{data}</td>
</tr>
</tbody>

View File

@@ -1,5 +1,5 @@
import {Component} from 'react';
import {getIPCRenderer} from '../../utils';
import { Component } from 'react';
import { getIPCRenderer } from '../../utils.jsx';
const ipcRenderer = getIPCRenderer();
@@ -16,7 +16,7 @@ export default class IPCContainer extends Component {
}
this.handlerList = {};
};
}
sendRequest = (name, data) => {
if (ipcRenderer) {
@@ -41,5 +41,4 @@ export default class IPCContainer extends Component {
ipcRenderer.on(name, callback);
}
};
};
}

View File

@@ -16,4 +16,4 @@ input.MountItemInput {
color: var(--text_color);
box-sizing: border-box;
width: 100%;
}
}

View File

@@ -1,6 +1,6 @@
import React from 'react';
import './MountItem.css';
import {connect} from 'react-redux';
import { connect } from 'react-redux';
import DropDown from '../../../components/UI/DropDown/DropDown';
import Button from '../../../components/UI/Button/Button';
import Loader from 'react-loader-spinner';
@@ -11,36 +11,41 @@ import RootElem from '../../../components/UI/RootElem/RootElem';
import {
displayConfiguration,
removeMount,
setProviderState
setProviderState,
} from '../../../redux/actions/mount_actions';
import {
displaySkynetExport,
displaySkynetImport,
} from '../../../redux/actions/skynet_actions'
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import { faTrashAlt} from '@fortawesome/free-solid-svg-icons';
} from '../../../redux/actions/skynet_actions';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import CheckBox from '../../../components/UI/CheckBox/CheckBox';
const mapStateToProps = (state, ownProps) => {
return {
MState: state.mounts.MountState[ownProps.provider],
Platform: state.common.Platform,
PState: state.mounts.ProviderState[ownProps.provider]
PState: state.mounts.ProviderState[ownProps.provider],
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
displayConfiguration: (provider, remote, s3) => dispatch(displayConfiguration(provider, remote, s3)),
displaySkynetExport: display => dispatch(displaySkynetExport(display)),
displaySkynetImport: display => dispatch(displaySkynetImport(display)),
removeMount: provider => dispatch(removeMount(provider)),
setProviderState: (provider, state) => dispatch(setProviderState(provider, state)),
}
displayConfiguration: (provider, remote, s3) =>
dispatch(displayConfiguration(provider, remote, s3)),
displaySkynetExport: (display) => dispatch(displaySkynetExport(display)),
displaySkynetImport: (display) => dispatch(displaySkynetImport(display)),
removeMount: (provider) => dispatch(removeMount(provider)),
setProviderState: (provider, state) =>
dispatch(setProviderState(provider, state)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(props => {
const handleAutoMountChanged = e => {
export default connect(
mapStateToProps,
mapDispatchToProps
)((props) => {
const handleAutoMountChanged = (e) => {
const state = {
...props.PState,
AutoMount: e.target.checked,
@@ -48,7 +53,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
props.setProviderState(props.provider, state);
};
const handleAutoRestartChanged = e => {
const handleAutoRestartChanged = (e) => {
const state = {
...props.PState,
AutoRestart: e.target.checked,
@@ -57,18 +62,28 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
};
let secondRow = 6;
const pointer = {cursor: props.MState.AllowMount ? 'pointer' : 'no-drop'};
const pointer = { cursor: props.MState.AllowMount ? 'pointer' : 'no-drop' };
const configButton = (
<RootElem colSpan={4}
rowSpan={6}>
<img alt=''
height={'16px'}
onClick={props.MState.AllowMount ? () => props.displayConfiguration(props.provider, props.remote, props.s3) : e => {
e.preventDefault();
}}
src={configureImage}
style={{padding: 0, border: 0, margin: 0, ...pointer}}
width={'16px'}/>
<RootElem colSpan={4} rowSpan={6}>
<img
alt=""
height={'16px'}
onClick={
props.MState.AllowMount
? () =>
props.displayConfiguration(
props.provider,
props.remote,
props.s3
)
: (e) => {
e.preventDefault();
}
}
src={configureImage}
style={{ padding: 0, border: 0, margin: 0, ...pointer }}
width={'16px'}
/>
</RootElem>
);
@@ -77,80 +92,119 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
if (props.Platform === 'win32') {
inputColumnSpan = 20;
const index = props.MState.DriveLetters.indexOf(props.PState.MountLocation);
inputControls = <DropDown changed={props.changed}
colSpan={inputColumnSpan}
disabled={!props.MState.AllowMount || props.MState.Mounted}
items={props.MState.DriveLetters}
row={secondRow}
rowSpan={7}
selected={index >= 0 ? props.PState.MountLocation : ''}/>;
inputControls = (
<DropDown
changed={props.changed}
colSpan={inputColumnSpan}
disabled={!props.MState.AllowMount || props.MState.Mounted}
items={props.MState.DriveLetters}
row={secondRow}
rowSpan={7}
selected={index >= 0 ? props.PState.MountLocation : ''}
/>
);
} else {
inputColumnSpan = 64;
inputControls = [];
let key = 0;
inputControls.push((
<RootElem colSpan={inputColumnSpan - 8}
key={'i' + key++}
row={secondRow}
rowSpan={7}>
<input disabled={!props.MState.AllowMount || props.MState.Mounted}
maxLength={4096}
onChange={props.changed}
size={4096}
className={'MountItemInput'}
type={'text'}
value={props.PState.MountLocation}/>
inputControls.push(
<RootElem
colSpan={inputColumnSpan - 8}
key={'i' + key++}
row={secondRow}
rowSpan={7}
>
<input
disabled={!props.MState.AllowMount || props.MState.Mounted}
maxLength={4096}
onChange={props.changed}
size={4096}
className={'MountItemInput'}
type={'text'}
value={props.PState.MountLocation}
/>
</RootElem>
));
inputControls.push((
<Button clicked={()=>props.browseClicked(props.provider, props.PState.MountLocation)}
col={inputColumnSpan - 7}
colSpan={7}
disabled={props.MState.Mounted || !props.MState.AllowMount}
key={'b' + key++}
row={secondRow}
rowSpan={7}>...</Button>
));
);
inputControls.push(
<Button
clicked={() =>
props.browseClicked(props.provider, props.PState.MountLocation)
}
col={inputColumnSpan - 7}
colSpan={7}
disabled={props.MState.Mounted || !props.MState.AllowMount}
key={'b' + key++}
row={secondRow}
rowSpan={7}
>
...
</Button>
);
}
const buttonDisplay = props.MState.AllowMount ?
(props.MState.Mounted ? 'Unmount' : 'Mount') :
<Loader color={'var(--heading_text_color)'}
height={19}
type='Circles'
width={19}/>;
const buttonDisplay = props.MState.AllowMount ? (
props.MState.Mounted ? (
'Unmount'
) : (
'Mount'
)
) : (
<Loader
color={'var(--heading_text_color)'}
height={19}
type="Circles"
width={19}
/>
);
const actionsDisplay = (
<Button
clicked={() => props.clicked(props.provider, props.remote, props.s3, !props.MState.Mounted, props.PState.MountLocation)}
clicked={() =>
props.clicked(
props.provider,
props.remote,
props.s3,
!props.MState.Mounted,
props.PState.MountLocation
)
}
col={inputColumnSpan + 2}
colSpan={21}
disabled={!props.MState.AllowMount}
row={secondRow}
rowSpan={7}>
rowSpan={7}
>
{buttonDisplay}
</Button>);
</Button>
);
const autoMountControl = (
<RootElem col={inputColumnSpan + 24}
colSpan={28}
row={secondRow}
rowSpan={7}>
<CheckBox changed={handleAutoMountChanged}
checked={props.PState.AutoMount}
label={'Auto-mount'}/>
<RootElem
col={inputColumnSpan + 24}
colSpan={28}
row={secondRow}
rowSpan={7}
>
<CheckBox
changed={handleAutoMountChanged}
checked={props.PState.AutoMount}
label={'Auto-mount'}
/>
</RootElem>
);
const autoRestartControl = (
<RootElem col={inputColumnSpan + 24 + 28}
colSpan={24}
row={secondRow}
rowSpan={7}>
<CheckBox changed={handleAutoRestartChanged}
checked={props.PState.AutoRestart}
label={'Restart'}/>
<RootElem
col={inputColumnSpan + 24 + 28}
colSpan={24}
row={secondRow}
rowSpan={7}
>
<CheckBox
changed={handleAutoRestartChanged}
checked={props.PState.AutoRestart}
label={'Restart'}
/>
</RootElem>
);
@@ -158,7 +212,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
if (props.allowRemove) {
const removeDisabled = !props.MState.AllowMount || props.MState.Mounted;
const removeStyle = {
cursor: removeDisabled ? 'no-drop' : 'pointer'
cursor: removeDisabled ? 'no-drop' : 'pointer',
};
const handleRemoveMount = () => {
if (!removeDisabled) {
@@ -166,17 +220,18 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
}
};
removeControl = (
<RootElem col={dimensions=>dimensions.columns - 6}
row={secondRow + 3}>
<a href={'#'}
onClick={handleRemoveMount}
style={removeStyle}>
<FontAwesomeIcon icon={faTrashAlt}/>
<RootElem
col={(dimensions) => dimensions.columns - 6}
row={secondRow + 3}
>
<a href={'#'} onClick={handleRemoveMount} style={removeStyle}>
<FontAwesomeIcon icon={faTrashAlt} />
</a>
</RootElem>);
</RootElem>
);
}
const isSkynet = (props.provider === 'Skynet');
const isSkynet = props.provider === 'Skynet';
return (
<div className={'MountItem'}>
<Grid noScroll>
@@ -185,28 +240,49 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
col={configButton ? 6 : 0}
rowSpan={5}
colSpan={90}
text={props.remote ? props.provider.substr(6) : props.s3 ? props.provider.substr(2) : isSkynet ? props.provider + ' [EXPERIMENTAL]' : props.provider}
text={
props.remote
? props.provider.substr(6)
: props.s3
? props.provider.substr(2)
: isSkynet
? props.provider + ' [EXPERIMENTAL]'
: props.provider
}
textAlign={'Left'}
type={'Heading2'}/>
{(isSkynet && (props.MState.Mounted)) ? (
<a href={'#'}
col={(configButton ? 24 : 18) + 34}
onClick={props.MState.AllowMount ? () => props.displaySkynetExport(true) : e => {
e.preventDefault();
}}
rowSpan={5}
style={{...pointer, fontWeight: 'normal'}}>
type={'Heading2'}
/>
{isSkynet && props.MState.Mounted ? (
<a
href={'#'}
col={(configButton ? 24 : 18) + 34}
onClick={
props.MState.AllowMount
? () => props.displaySkynetExport(true)
: (e) => {
e.preventDefault();
}
}
rowSpan={5}
style={{ ...pointer, fontWeight: 'normal' }}
>
<u>Export</u>
</a>
) : null}
{(isSkynet && (props.MState.Mounted)) ? (
<a href={'#'}
col={(configButton ? 24 + 13 : 18 + 13) + 34}
onClick={props.MState.AllowMount ? () => props.displaySkynetImport(true) : e => {
e.preventDefault();
}}
rowSpan={5}
style={{...pointer, fontWeight: 'normal'}}>
{isSkynet && props.MState.Mounted ? (
<a
href={'#'}
col={(configButton ? 24 + 13 : 18 + 13) + 34}
onClick={
props.MState.AllowMount
? () => props.displaySkynetImport(true)
: (e) => {
e.preventDefault();
}
}
rowSpan={5}
style={{ ...pointer, fontWeight: 'normal' }}
>
<u>Import</u>
</a>
) : null}

View File

@@ -15,4 +15,4 @@
box-sizing: border-box;
overflow-x: hidden;
overflow-y: scroll;
}
}

View File

@@ -2,7 +2,7 @@ import React from 'react';
import AddMount from '../AddMount/AddMount';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import {connect} from 'react-redux';
import { connect } from 'react-redux';
import './MountItems.css';
import Modal from '../../components/UI/Modal/Modal';
import MountItem from './MountItem/MountItem';
@@ -14,9 +14,9 @@ import {
setBusy,
setMounted,
setMountState,
setProviderState
setProviderState,
} from '../../redux/actions/mount_actions';
import {notifyError} from '../../redux/actions/error_actions';
import { notifyError } from '../../redux/actions/error_actions';
const Constants = require('../../constants');
@@ -29,7 +29,7 @@ class MountItems extends IPCContainer {
RetryItems: {},
};
addMountsBusy = provider => {
addMountsBusy = (provider) => {
this.props.setMountsBusy(true);
this.activeDetections.push(provider);
};
@@ -43,22 +43,34 @@ class MountItems extends IPCContainer {
...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);
this.setState(
{
DisplayRetry: Object.keys(retryItems).length > 0,
RetryItems: retryItems,
},
() => {
if (this.state.DisplayRetry) {
this.sendRequest(Constants.IPC_Show_Window);
}
stateCallback();
}
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.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();
}
@@ -73,9 +85,9 @@ class MountItems extends IPCContainer {
this.props.resetMountsState();
this.activeDetections = [];
super.componentWillUnmount();
};
}
detectMount = provider => {
detectMount = (provider) => {
this.addMountsBusy(provider);
this.sendRequest(Constants.IPC_Detect_Mount, {
@@ -86,10 +98,10 @@ class MountItems extends IPCContainer {
});
};
detectMounts = ()=> {
detectMounts = () => {
if (!this.state.DisplayRetry) {
const providerList = this.getProviderList();
providerList.forEach(provider => {
providerList.forEach((provider) => {
this.detectMount(provider);
});
}
@@ -98,7 +110,7 @@ class MountItems extends IPCContainer {
displayRetryMount = (provider, remote, s3, mountLocation, msg) => {
if (!this.state.RetryItems[provider]) {
let retryItems = {
...this.state.RetryItems
...this.state.RetryItems,
};
retryItems[provider] = {
RetrySeconds: 10,
@@ -110,28 +122,37 @@ class MountItems extends IPCContainer {
};
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, s3, true, mountLocation);
});
} else {
retryItems[provider].RetrySeconds = retrySeconds;
this.setState({
RetryItems: retryItems,
});
}
}, 1000);
});
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,
s3,
true,
mountLocation
);
});
} else {
retryItems[provider].RetrySeconds = retrySeconds;
this.setState({
RetryItems: retryItems,
});
}
}, 1000);
}
);
}
};
@@ -140,7 +161,7 @@ class MountItems extends IPCContainer {
Title: provider + ' Mount Location',
Location: location,
});
if (location && (location.length > 0)) {
if (location && location.length > 0) {
this.handleMountLocationChanged(provider, location);
}
};
@@ -154,25 +175,29 @@ class MountItems extends IPCContainer {
};
handleMountUnMount = (provider, remote, s3, mount, location) => {
if (!location || (location.trim().length === 0)) {
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;
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;
if (result.Success) {
if (result.Valid) {
if (this.props.Platform !== 'win32') {
result = this.sendSyncRequest(Constants.IPC_Check_Mount_Location, {
Location: location,
});
result = this.sendSyncRequest(
Constants.IPC_Check_Mount_Location,
{
Location: location,
}
);
if (!result.Success) {
allowAction = false;
this.props.notifyError(result.Error.toString());
@@ -180,20 +205,56 @@ class MountItems extends IPCContainer {
}
} else {
allowAction = false;
if ((result.Code === new Uint32Array([-1])[0]) || (result.Code === new Uint8Array([-1])[0])) {
this.displayRetryMount(provider, remote, s3, 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, s3, location, 'Incompatible ' + provider + ' daemon. Please upgrade ' + provider + '.');
if (
result.Code === new Uint32Array([-1])[0] ||
result.Code === new Uint8Array([-1])[0]
) {
this.displayRetryMount(
provider,
remote,
s3,
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,
s3,
location,
'Incompatible ' +
provider +
' daemon. Please upgrade ' +
provider +
'.'
);
} else {
this.displayRetryMount(provider, remote, s3, location, 'Version check failed: ' + result.Error);
this.displayRetryMount(
provider,
remote,
s3,
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.');
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, s3, location, 'Version check failed: ' + result.Error);
this.displayRetryMount(
provider,
remote,
s3,
location,
'Version check failed: ' + result.Error
);
}
}
}
@@ -223,11 +284,13 @@ class MountItems extends IPCContainer {
}
};
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);
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 = [];
@@ -240,17 +303,12 @@ class MountItems extends IPCContainer {
s3List = [...this.props.S3Mounts];
}
return [
...providerList,
...remoteList,
...s3List,
];
return [...providerList, ...remoteList, ...s3List];
};
hasActiveMount = () => {
for (const provider of Object.keys(this.props.MountState)) {
if (this.props.MountState[provider].Mounted)
return true;
if (this.props.MountState[provider].Mounted) return true;
}
return false;
@@ -259,7 +317,11 @@ class MountItems extends IPCContainer {
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)))) {
if (
arg.data.Success &&
(!arg.data.Active ||
(arg.data.Location && arg.data.Location.length > 0))
) {
const mountState = {
AllowMount: true,
DriveLetters: arg.data.DriveLetters,
@@ -267,7 +329,12 @@ class MountItems extends IPCContainer {
};
this.props.setMountState(provider, mountState);
this.updateMountLocation(provider, arg.data.Location, mountState.Mounted, arg.data.DriveLetters);
this.updateMountLocation(
provider,
arg.data.Location,
mountState.Mounted,
arg.data.DriveLetters
);
this.props.setAutoMountProcessed(provider, true);
this.removeMountsBusy(provider);
} else {
@@ -284,39 +351,63 @@ class MountItems extends IPCContainer {
};
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);
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 => {
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());
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;
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] &&
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);
location.length > 0
) {
this.handleMountUnMount(
provider,
this.props.RemoteMounts.includes(provider),
this.props.S3Mounts.includes(provider),
true,
location
);
}
};
@@ -328,104 +419,162 @@ class MountItems extends IPCContainer {
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(
<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>);
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}/>);
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>
<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 || this.props.s3Supported) {
footerItems.push(<AddMount remoteSupported={this.props.remoteSupported}
s3Supported={this.props.s3Supported}
key={'hi_' + footerItems.length}/>);
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'}}/>);
footerItems.push(
<div key={'hi_' + footerItems.length} style={{ height: '27px' }} />
);
}
let items = [];
for (const provider of this.getProviderList(true)) {
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)'}} />)
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.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)' }}
/>
);
}
}
if (this.props.s3Supported) {
for (const provider of this.props.S3Mounts) {
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}
s3/>
));
items.push(<div key={'it_' + items.length}
style={{paddingTop: 'var(--default_spacing)'}}/>)
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}
s3
/>
);
items.push(
<div
key={'it_' + items.length}
style={{ paddingTop: 'var(--default_spacing)' }}
/>
);
}
}
items.splice(items.length - 1, 1);
return (
<div style={{margin: 0, padding: 0}}>
<div style={{ margin: 0, padding: 0 }}>
{retryDisplay}
<div
className={this.props.remoteSupported || this.props.s3Supported ? 'MountItemsRemote' : 'MountItems'}>
className={
this.props.remoteSupported || this.props.s3Supported
? 'MountItemsRemote'
: 'MountItems'
}
>
{items}
</div>
<div style={{paddingTop: 'var(--default_spacing)'}}/>
<div style={{ paddingTop: 'var(--default_spacing)' }} />
{footerItems}
</div>);
</div>
);
}
}
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
AutoMountProcessed: state.mounts.AutoMountProcessed,
InstalledVersion: state.relver.InstalledVersion,
@@ -435,20 +584,25 @@ const mapStateToProps = state => {
ProviderState: state.mounts.ProviderState,
RemoteMounts: state.mounts.RemoteMounts,
S3Mounts: state.mounts.S3Mounts,
}
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
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)),
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)),
}
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);

View File

@@ -1,180 +1,227 @@
import React from 'react';
import './PinnedManager.css';
import {connect} from 'react-redux';
import { connect } from 'react-redux';
import IPCContainer from '../IPCContainer/IPCContainer';
import {notifyApplicationBusy} from '../../redux/actions/common_actions';
import {notifyError, notifyInfo} from '../../redux/actions/error_actions';
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
import Box from '../../components/UI/Box/Box';
import {displayPinnedManager} from '../../redux/actions/pinned_manager_actions';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faFolder} from '@fortawesome/free-solid-svg-icons';
import { displayPinnedManager } from '../../redux/actions/pinned_manager_actions';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faFolder } from '@fortawesome/free-solid-svg-icons';
import Button from '../../components/UI/Button/Button';
import CheckBox from '../../components/UI/CheckBox/CheckBox';
const Constants = require('../../constants');
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
DisplayConfiguration: state.mounts.DisplayConfiguration,
DisplayRemoteConfiguration: state.mounts.DisplayRemoteConfiguration,
DisplayS3Configuration: state.mounts.DisplayS3Configuration,
}
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
displayPinnedManager: display => dispatch(displayPinnedManager(display)),
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
displayPinnedManager: (display) => dispatch(displayPinnedManager(display)),
notifyApplicationBusy: (busy) =>
dispatch(notifyApplicationBusy(busy, true)),
notifyError: (msg, cb) => dispatch(notifyError(msg, false, cb)),
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCContainer {
state = {
active_directory: '/',
items: [],
previous: [],
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(
class extends IPCContainer {
state = {
active_directory: '/',
items: [],
previous: [],
};
componentDidMount() {
this.setRequestHandler(Constants.IPC_Get_Directory_Items_Reply, this.onGetDirectoryItemsReply);
this.grabDirectoryItems();
}
componentWillUnmount() {
super.componentWillUnmount();
}
grabDirectoryItems = () => {
this.sendRequest(Constants.IPC_Get_Directory_Items, {
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
Path: this.state.active_directory,
});
}
onGetDirectoryItemsReply = (_, {data}) => {
if (data.Success) {
const items = data.Items
.filter(i => i.path !== '.' && (this.state.active_directory !== '/' || (i.path.substr(0, 1) !== '.')))
.map(i => {
return {
...i,
name: i.path === '..' ? i.path : i.path.substr(i.path.lastIndexOf('/') + 1),
meta: {
...i.meta,
pinned: i.meta.pinned === '1',
}
}
});
this.setState({
items,
});
} else {
this.props.notifyError(data.Error, () => {
this.props.displayPinnedManager(false);
});
componentDidMount() {
this.setRequestHandler(
Constants.IPC_Get_Directory_Items_Reply,
this.onGetDirectoryItemsReply
);
this.grabDirectoryItems();
}
}
createDirectory = (name, path, idx, total, item_idx) => {
const style = {}
if (item_idx + 1 !== total) {
style.marginBottom = '4px';
componentWillUnmount() {
super.componentWillUnmount();
}
return (
<div key={'dir_' + idx} style={{...style}}>
<Button buttonStyles={{textAlign: 'left'}}
clicked={() => {
const previous = [...this.state.previous];
if (path === '..') {
path = previous.pop();
} else {
previous.push(this.state.active_directory);
}
this.setState({
items: [],
active_directory: path,
previous,
}, () => {
this.grabDirectoryItems();
});
}}>
<FontAwesomeIcon icon={faFolder}
fixedWidth
color={'var(--heading_text_color)'}
style={{padding: 0, margin: 0}}/>
&nbsp;{name}
</Button>
</div>
);
}
createFile = (name, path, pinned, idx, total, item_idx) => {
const style = {textAlign: 'left'}
if (item_idx + 1 !== total) {
style.marginBottom = '2px';
}
return (
<div key={'file_' + idx} style={{...style}}>
<CheckBox checked={pinned}
changed={() => {
const items = JSON.parse(JSON.stringify(this.state.items));
const pinned = items[item_idx].meta.pinned = !items[item_idx].meta.pinned;
this.setState({
items
}, () => {
this.sendSyncRequest(Constants.IPC_Set_Pinned, {
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
Path: path,
Pinned: pinned,
});
});
}}
label={name}/>
</div>
);
}
grabDirectoryItems = () => {
this.sendRequest(Constants.IPC_Get_Directory_Items, {
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
Path: this.state.active_directory,
});
};
render() {
let idx = 0;
return (
<Box dxDark dxStyle={{
height: 'calc(100vh - (var(--default_spacing) * 4)',
padding: 'var(--default_spacing)',
width: 'calc(100vw - (var(--default_spacing) * 4)'
}}>
<div className={'PinnedManager'}>
<div className={'PinnedManagerHeading'}>
<div className={'PinnedManagerClose'}>
<a href={'#'}
onClick={() => this.props.displayPinnedManager(false)}
style={{cursor: 'pointer', flex: '0'}}>X</a>
</div>
<h1 style={{width: '100%', textAlign: 'center'}}>{'Pinned File Manager'}</h1>
<div className={'PinnedManagerActiveDirectory'}>
<b>&nbsp;{this.state.active_directory}</b>
</div>
</div>
<div className={'PinnedManagerItemsOwner'}>
<div className={'PinnedManagerItems'}>
{
this.state.items.map((i, k) => {
return i.directory ?
this.createDirectory(i.name, i.path, idx++, this.state.items.length, k) :
this.createFile(i.name, i.path, i.meta.pinned, idx++, this.state.items.length, k);
})
onGetDirectoryItemsReply = (_, { data }) => {
if (data.Success) {
const items = data.Items.filter(
(i) =>
i.path !== '.' &&
(this.state.active_directory !== '/' || i.path.substr(0, 1) !== '.')
).map((i) => {
return {
...i,
name:
i.path === '..'
? i.path
: i.path.substr(i.path.lastIndexOf('/') + 1),
meta: {
...i.meta,
pinned: i.meta.pinned === '1',
},
};
});
this.setState({
items,
});
} else {
this.props.notifyError(data.Error, () => {
this.props.displayPinnedManager(false);
});
}
};
createDirectory = (name, path, idx, total, item_idx) => {
const style = {};
if (item_idx + 1 !== total) {
style.marginBottom = '4px';
}
return (
<div key={'dir_' + idx} style={{ ...style }}>
<Button
buttonStyles={{ textAlign: 'left' }}
clicked={() => {
const previous = [...this.state.previous];
if (path === '..') {
path = previous.pop();
} else {
previous.push(this.state.active_directory);
}
this.setState(
{
items: [],
active_directory: path,
previous,
},
() => {
this.grabDirectoryItems();
}
);
}}
>
<FontAwesomeIcon
icon={faFolder}
fixedWidth
color={'var(--heading_text_color)'}
style={{ padding: 0, margin: 0 }}
/>
&nbsp;{name}
</Button>
</div>
);
};
createFile = (name, path, pinned, idx, total, item_idx) => {
const style = { textAlign: 'left' };
if (item_idx + 1 !== total) {
style.marginBottom = '2px';
}
return (
<div key={'file_' + idx} style={{ ...style }}>
<CheckBox
checked={pinned}
changed={() => {
const items = JSON.parse(JSON.stringify(this.state.items));
const pinned = (items[item_idx].meta.pinned = !items[item_idx]
.meta.pinned);
this.setState(
{
items,
},
() => {
this.sendSyncRequest(Constants.IPC_Set_Pinned, {
Provider: this.props.DisplayConfiguration,
Remote: this.props.DisplayRemoteConfiguration,
S3: this.props.DisplayS3Configuration,
Version: this.props.version,
Path: path,
Pinned: pinned,
});
}
);
}}
label={name}
/>
</div>
);
};
render() {
let idx = 0;
return (
<Box
dxDark
dxStyle={{
height: 'calc(100vh - (var(--default_spacing) * 4)',
padding: 'var(--default_spacing)',
width: 'calc(100vw - (var(--default_spacing) * 4)',
}}
>
<div className={'PinnedManager'}>
<div className={'PinnedManagerHeading'}>
<div className={'PinnedManagerClose'}>
<a
href={'#'}
onClick={() => this.props.displayPinnedManager(false)}
style={{ cursor: 'pointer', flex: '0' }}
>
X
</a>
</div>
<h1 style={{ width: '100%', textAlign: 'center' }}>
{'Pinned File Manager'}
</h1>
<div className={'PinnedManagerActiveDirectory'}>
<b>&nbsp;{this.state.active_directory}</b>
</div>
</div>
<div className={'PinnedManagerItemsOwner'}>
<div className={'PinnedManagerItems'}>
{this.state.items.map((i, k) => {
return i.directory
? this.createDirectory(
i.name,
i.path,
idx++,
this.state.items.length,
k
)
: this.createFile(
i.name,
i.path,
i.meta.pinned,
idx++,
this.state.items.length,
k
);
})}
</div>
</div>
</div>
</div>
</Box>
)
</Box>
);
}
}
});
);

View File

@@ -1,43 +1,50 @@
import React from 'react';
import './SelectAppPlatform.css';
import axios from 'axios';
import {connect} from 'react-redux';
import { connect } from 'react-redux';
import * as Constants from '../../constants';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import {
downloadItem,
setAllowDownload
setAllowDownload,
} from '../../redux/actions/download_actions';
import DropDown from '../../components/UI/DropDown/DropDown';
import IPCContainer from '../IPCContainer/IPCContainer';
import {notifyError} from '../../redux/actions/error_actions';
import {setInstallTestActive} from '../../redux/actions/install_actions';
import { notifyError } from '../../redux/actions/error_actions';
import { setInstallTestActive } from '../../redux/actions/install_actions';
class SelectAppPlatform extends IPCContainer {
state = {
Selected: 0,
};
grabLatestRelease = appPlatform => {
const errorHandler = error => {
grabLatestRelease = (appPlatform) => {
const errorHandler = (error) => {
this.props.notifyError(error);
this.props.setInstallTestActive(false);
this.props.setAllowDownload(false);
};
axios
.get(Constants.RELEASES_URL)
.then(response => {
.then((response) => {
try {
const releases = response.data.Versions.Release[appPlatform];
const latestVersion = releases[releases.length - 1];
const release = response.data.Locations[appPlatform][latestVersion];
this.props.downloadItem(latestVersion + '.zip', Constants.INSTALL_TYPES.TestRelease, release.urls, false, latestVersion, appPlatform);
this.props.downloadItem(
latestVersion + '.zip',
Constants.INSTALL_TYPES.TestRelease,
release.urls,
false,
latestVersion,
appPlatform
);
} catch (error) {
errorHandler(error);
}
})
.catch(error => {
.catch((error) => {
errorHandler(error);
});
};
@@ -45,10 +52,12 @@ class SelectAppPlatform extends IPCContainer {
handleTestClicked = () => {
this.props.setInstallTestActive(true);
this.props.setAllowDownload(true);
this.grabLatestRelease(Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected])
this.grabLatestRelease(
Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]
);
};
handleChanged = e => {
handleChanged = (e) => {
this.setState({
...this.state,
Selected: Constants.LINUX_SELECTABLE_PLATFORMS.indexOf(e.target.value),
@@ -57,37 +66,49 @@ class SelectAppPlatform extends IPCContainer {
render() {
return (
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
<h1 className={'SAPHeading'}>Select Linux Platform</h1>
<div className={'SAPContent'}>
<p>Repertory was unable to detect your Linux distribution. Please select one of the following and click <b>Test</b> to continue:</p>
<p>
Repertory was unable to detect your Linux distribution. Please
select one of the following and click <b>Test</b> to continue:
</p>
</div>
<div className={'SAPActions'}>
<DropDown changed={this.handleChanged}
disabled={this.props.InstallTestActive}
items={Constants.LINUX_SELECTABLE_PLATFORMS}
selected={Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]}/>
<Button clicked={this.handleTestClicked}
disabled={this.props.InstallTestActive}>Test</Button>
<DropDown
changed={this.handleChanged}
disabled={this.props.InstallTestActive}
items={Constants.LINUX_SELECTABLE_PLATFORMS}
selected={Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]}
/>
<Button
clicked={this.handleTestClicked}
disabled={this.props.InstallTestActive}
>
Test
</Button>
</div>
</Box>
);
}
}
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
InstallTestActive: state.install.InstallTestActive,
}
};
const mapDispatchToProps = dispatch => {
return {
downloadItem: (name, type, urls, isWinFSP, testVersion, appPlatform) => dispatch(downloadItem(name, type, urls, isWinFSP, testVersion, appPlatform)),
notifyError: msg => dispatch(notifyError(msg)),
setAllowDownload: allow => dispatch(setAllowDownload(allow)),
setInstallTestActive: active => dispatch(setInstallTestActive(active)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(SelectAppPlatform);
const mapDispatchToProps = (dispatch) => {
return {
downloadItem: (name, type, urls, isWinFSP, testVersion, appPlatform) =>
dispatch(
downloadItem(name, type, urls, isWinFSP, testVersion, appPlatform)
),
notifyError: (msg) => dispatch(notifyError(msg)),
setAllowDownload: (allow) => dispatch(setAllowDownload(allow)),
setInstallTestActive: (active) => dispatch(setInstallTestActive(active)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(SelectAppPlatform);

View File

@@ -1,59 +1,78 @@
import React from 'react';
import './SkynetExport.css';
import CheckboxTree from 'react-checkbox-tree';
import {connect} from 'react-redux';
import { connect } from 'react-redux';
import IPCContainer from '../IPCContainer/IPCContainer';
import {notifyApplicationBusy} from '../../redux/actions/common_actions';
import {notifyError, notifyInfo} from '../../redux/actions/error_actions';
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
import Box from '../../components/UI/Box/Box';
import {displaySkynetExport} from '../../redux/actions/skynet_actions';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import { displaySkynetExport } from '../../redux/actions/skynet_actions';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faCheckSquare, faChevronDown,
faChevronRight, faFile, faFolder, faFolderOpen,
faHSquare, faMinusSquare, faPlusSquare,
faSquare
faCheckSquare,
faChevronDown,
faChevronRight,
faFile,
faFolder,
faFolderOpen,
faHSquare,
faMinusSquare,
faPlusSquare,
faSquare,
} from '@fortawesome/free-solid-svg-icons';
import Button from '../../components/UI/Button/Button';
const Constants = require('../../constants');
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
AppBusy: state.common.AppBusy,
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
displaySkynetExport: display => dispatch(displaySkynetExport(display)),
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
notifyError: msg => dispatch(notifyError(msg)),
displaySkynetExport: (display) => dispatch(displaySkynetExport(display)),
notifyApplicationBusy: (busy) =>
dispatch(notifyApplicationBusy(busy, true)),
notifyError: (msg) => dispatch(notifyError(msg)),
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCContainer {
state = {
checked: [],
clicked: {},
expanded: [],
nodes: [],
second_stage: false,
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(
class extends IPCContainer {
state = {
checked: [],
clicked: {},
expanded: [],
nodes: [],
second_stage: false,
};
componentDidMount() {
this.setRequestHandler(Constants.IPC_Grab_Skynet_Tree_Reply, this.onGrabSkynetTreeReply);
this.setRequestHandler(Constants.IPC_Export_Skylinks_Reply, this.onExportSkylinksReply);
this.sendRequest(Constants.IPC_Grab_Skynet_Tree, {Version: this.props.version});
}
componentDidMount() {
this.setRequestHandler(
Constants.IPC_Grab_Skynet_Tree_Reply,
this.onGrabSkynetTreeReply
);
this.setRequestHandler(
Constants.IPC_Export_Skylinks_Reply,
this.onExportSkylinksReply
);
this.sendRequest(Constants.IPC_Grab_Skynet_Tree, {
Version: this.props.version,
});
}
componentWillUnmount() {
super.componentWillUnmount();
}
componentWillUnmount() {
super.componentWillUnmount();
}
createNodes = items => {
/*
createNodes = (items) => {
/*
{
name: '',
path: '',
@@ -61,175 +80,269 @@ export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCCon
children: [],
}
*/
const ret = [];
for (const item of items) {
const treeItem = {
label: item.name,
path: item.path,
value: item.name === '/' ? 0 : item.path ? item.path : JSON.stringify(item),
};
const ret = [];
for (const item of items) {
const treeItem = {
label: item.name,
path: item.path,
value:
item.name === '/'
? 0
: item.path
? item.path
: JSON.stringify(item),
};
if (item.directory) {
treeItem.children = this.createNodes(item.children);
if (item.directory) {
treeItem.children = this.createNodes(item.children);
}
ret.push(treeItem);
}
ret.push(treeItem);
}
return ret;
};
return ret;
}
handleNavigation = () => {
if (this.state.second_stage) {
this.props.notifyApplicationBusy(true);
this.sendRequest(Constants.IPC_Export_Skylinks, {
Version: this.props.version,
Paths: this.state.checked,
});
} else {
if (this.state.checked.length === 0) {
this.props.notifyError('No files have been checked');
} else {
this.setState({
second_stage: true,
handleNavigation = () => {
if (this.state.second_stage) {
this.props.notifyApplicationBusy(true);
this.sendRequest(Constants.IPC_Export_Skylinks, {
Version: this.props.version,
Paths: this.state.checked,
});
} else {
if (this.state.checked.length === 0) {
this.props.notifyError('No files have been checked');
} else {
this.setState({
second_stage: true,
});
}
}
}
}
};
onExportSkylinksReply = (_, arg) => {
this.props.notifyApplicationBusy(false);
if (arg.data.Success) {
this.setState({
checked: [],
clicked: {},
expanded: [],
nodes: [],
second_stage: false,
}, () => {
this.props.notifyInfo('Skylink Exports', '!alternate!!copyable!' + JSON.stringify(arg.data.Result.success, null, 2));
this.sendRequest(Constants.IPC_Grab_Skynet_Tree, {Version: this.props.version});
});
} else {
this.props.notifyError(arg.data.Error);
}
}
onGrabSkynetTreeReply = (_, arg) => {
if (arg.data.Success) {
this.setState({
checked: [],
expanded: [0],
nodes: this.createNodes(arg.data.Result),
});
} else {
this.setState({
checked: [],
expanded: [],
nodes: [],
}, () => {
this.props.notifyError(arg.data.Error);
});
}
}
render() {
return this.props.AppBusy ? (<div/>) : (
<Box dxDark dxStyle={{
height: '90vh',
padding: 'var(--default_spacing)',
width: 'calc(100vw - (var(--default_spacing) * 4)'
}}>
<div
style={{
float: 'right',
margin: 0,
padding: 0,
marginTop: '-4px',
boxSizing: 'border-box',
display: 'block'
}}>
<a href={'#'}
onClick={() => this.props.displaySkynetExport(false)}
style={{cursor: 'pointer'}}>X</a>
</div>
<h1
className={'SkynetExportHeading'}>{this.state.second_stage ? 'Verify Exports' : 'Export Files'}</h1>
<div className={this.state.second_stage ? 'SkynetExportList' : 'SkynetExportTree'}>
onExportSkylinksReply = (_, arg) => {
this.props.notifyApplicationBusy(false);
if (arg.data.Success) {
this.setState(
{
this.state.second_stage ?
this.state.checked.map(path => {
checked: [],
clicked: {},
expanded: [],
nodes: [],
second_stage: false,
},
() => {
this.props.notifyInfo(
'Skylink Exports',
'!alternate!!copyable!' +
JSON.stringify(arg.data.Result.success, null, 2)
);
this.sendRequest(Constants.IPC_Grab_Skynet_Tree, {
Version: this.props.version,
});
}
);
} else {
this.props.notifyError(arg.data.Error);
}
};
onGrabSkynetTreeReply = (_, arg) => {
if (arg.data.Success) {
this.setState({
checked: [],
expanded: [0],
nodes: this.createNodes(arg.data.Result),
});
} else {
this.setState(
{
checked: [],
expanded: [],
nodes: [],
},
() => {
this.props.notifyError(arg.data.Error);
}
);
}
};
render() {
return this.props.AppBusy ? (
<div />
) : (
<Box
dxDark
dxStyle={{
height: '90vh',
padding: 'var(--default_spacing)',
width: 'calc(100vw - (var(--default_spacing) * 4)',
}}
>
<div
style={{
float: 'right',
margin: 0,
padding: 0,
marginTop: '-4px',
boxSizing: 'border-box',
display: 'block',
}}
>
<a
href={'#'}
onClick={() => this.props.displaySkynetExport(false)}
style={{ cursor: 'pointer' }}
>
X
</a>
</div>
<h1 className={'SkynetExportHeading'}>
{this.state.second_stage ? 'Verify Exports' : 'Export Files'}
</h1>
<div
className={
this.state.second_stage ? 'SkynetExportList' : 'SkynetExportTree'
}
>
{this.state.second_stage ? (
this.state.checked.map((path) => {
return (
<input readOnly
className={'ConfigurationItemInput'}
key={path}
style={{width: '100%', marginBottom: 'var(--default_spacing)'}}
type={'text'}
value={path}/>
<input
readOnly
className={'ConfigurationItemInput'}
key={path}
style={{
width: '100%',
marginBottom: 'var(--default_spacing)',
}}
type={'text'}
value={path}
/>
);
})
: (
<CheckboxTree checked={this.state.checked}
expanded={this.state.expanded}
expandOnClick
showExpandAll
icons={{
check: <FontAwesomeIcon icon={faCheckSquare} fixedWidth
style={{padding: 0, margin: 0}}/>,
uncheck: <FontAwesomeIcon icon={faSquare} fixedWidth
style={{padding: 0, margin: 0}}/>,
halfCheck: <FontAwesomeIcon icon={faHSquare} fixedWidth
style={{padding: 0, margin: 0}}/>,
expandClose: <FontAwesomeIcon icon={faChevronRight} fixedWidth
style={{padding: 0, margin: 0}}/>,
expandOpen: <FontAwesomeIcon icon={faChevronDown} fixedWidth
style={{padding: 0, margin: 0}}/>,
expandAll: <FontAwesomeIcon icon={faPlusSquare} fixedWidth
style={{padding: 0, margin: 0}}/>,
collapseAll: <FontAwesomeIcon icon={faMinusSquare} fixedWidth
style={{padding: 0, margin: 0}}/>,
parentClose: <FontAwesomeIcon icon={faFolder}
fixedWidth
color={'var(--heading_text_color)'}
style={{padding: 0, margin: 0}}/>,
parentOpen: <FontAwesomeIcon icon={faFolderOpen}
fixedWidth
color={'var(--heading_text_color)'}
style={{padding: 0, margin: 0}}/>,
leaf: <FontAwesomeIcon icon={faFile}
fixedWidth
color={'var(--text_color)'}
style={{padding: 0, margin: 0}}/>
}}
nodes={this.state.nodes}
onClick={clicked => this.setState({clicked})}
onCheck={checked => this.setState({checked})}
onExpand={expanded => this.setState({expanded})}/>
)
}
</div>
<div style={{display: 'flex', justifyContent: 'flex-end'}}>
{
this.state.second_stage ?
<Button buttonStyles={{
) : (
<CheckboxTree
checked={this.state.checked}
expanded={this.state.expanded}
expandOnClick
showExpandAll
icons={{
check: (
<FontAwesomeIcon
icon={faCheckSquare}
fixedWidth
style={{ padding: 0, margin: 0 }}
/>
),
uncheck: (
<FontAwesomeIcon
icon={faSquare}
fixedWidth
style={{ padding: 0, margin: 0 }}
/>
),
halfCheck: (
<FontAwesomeIcon
icon={faHSquare}
fixedWidth
style={{ padding: 0, margin: 0 }}
/>
),
expandClose: (
<FontAwesomeIcon
icon={faChevronRight}
fixedWidth
style={{ padding: 0, margin: 0 }}
/>
),
expandOpen: (
<FontAwesomeIcon
icon={faChevronDown}
fixedWidth
style={{ padding: 0, margin: 0 }}
/>
),
expandAll: (
<FontAwesomeIcon
icon={faPlusSquare}
fixedWidth
style={{ padding: 0, margin: 0 }}
/>
),
collapseAll: (
<FontAwesomeIcon
icon={faMinusSquare}
fixedWidth
style={{ padding: 0, margin: 0 }}
/>
),
parentClose: (
<FontAwesomeIcon
icon={faFolder}
fixedWidth
color={'var(--heading_text_color)'}
style={{ padding: 0, margin: 0 }}
/>
),
parentOpen: (
<FontAwesomeIcon
icon={faFolderOpen}
fixedWidth
color={'var(--heading_text_color)'}
style={{ padding: 0, margin: 0 }}
/>
),
leaf: (
<FontAwesomeIcon
icon={faFile}
fixedWidth
color={'var(--text_color)'}
style={{ padding: 0, margin: 0 }}
/>
),
}}
nodes={this.state.nodes}
onClick={(clicked) => this.setState({ clicked })}
onCheck={(checked) => this.setState({ checked })}
onExpand={(expanded) => this.setState({ expanded })}
/>
)}
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
{this.state.second_stage ? (
<Button
buttonStyles={{
height: 'auto',
marginLeft: 'var(--default_spacing)',
marginTop: 'var(--default_spacing)',
width: 'auto',
}}
clicked={() =>
this.setState({
second_stage: false,
})
}
>
{'Back'}
</Button>
) : null}
<Button
buttonStyles={{
height: 'auto',
marginLeft: 'var(--default_spacing)',
marginTop: 'var(--default_spacing)',
width: 'auto'
}} clicked={() => this.setState({
second_stage: false,
})}>{'Back'}</Button> :
null
}
<Button buttonStyles={{
height: 'auto',
marginLeft: 'var(--default_spacing)',
marginTop: 'var(--default_spacing)',
width: 'auto'
}}
clicked={this.handleNavigation}>{this.state.second_stage ? 'Export' : 'Next'}</Button>
</div>
</Box>
);
width: 'auto',
}}
clicked={this.handleNavigation}
>
{this.state.second_stage ? 'Export' : 'Next'}
</Button>
</div>
</Box>
);
}
}
});
);

View File

@@ -1,30 +1,36 @@
import React from 'react'
import './Import.css'
import React from 'react';
import './Import.css';
const Import = ({data}) => {
const Import = ({ data }) => {
return (
<div className={'ImportOwner'}>
<input readOnly
className={'ConfigurationItemInput'}
style={{
maxWidth: 'calc(33.33% - var(--default_spacing)',
marginRight: 'var(--default_spacing)'
}}
type={'text'}
value={data.directory}/>
<input readOnly
className={'ConfigurationItemInput'}
style={{maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))'}}
type={'text'}
value={data.skylink}/>
<input readOnly
className={'ConfigurationItemInput'}
style={{
maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))',
marginLeft: 'var(--default_spacing)'
}}
type={'text'}
value={data.token}/>
<input
readOnly
className={'ConfigurationItemInput'}
style={{
maxWidth: 'calc(33.33% - var(--default_spacing)',
marginRight: 'var(--default_spacing)',
}}
type={'text'}
value={data.directory}
/>
<input
readOnly
className={'ConfigurationItemInput'}
style={{ maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))' }}
type={'text'}
value={data.skylink}
/>
<input
readOnly
className={'ConfigurationItemInput'}
style={{
maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))',
marginLeft: 'var(--default_spacing)',
}}
type={'text'}
value={data.token}
/>
</div>
);
};

View File

@@ -1,29 +1,38 @@
import React from 'react'
import './ImportList.css'
import Import from './Import/Import'
import React from 'react';
import './ImportList.css';
import Import from './Import/Import';
import Text from '../../../components/UI/Text/Text';
const ImportList = ({imports_array}) => {
const ImportList = ({ imports_array }) => {
let key = 0;
return (
<div>
<div className={'ImportListHeader'}>
<Text type={'Heading1'} text={'Directory'}
style={{minWidth: '33.33%', maxWidth: '33.33%'}}/>
<Text type={'Heading1'} text={'Skylink'} style={{minWidth: '33.33%', maxWidth: '33.33%'}}/>
<Text type={'Heading1'} text={'Token'} style={{minWidth: '33.33%', maxWidth: '33.33%'}}/>
<Text
type={'Heading1'}
text={'Directory'}
style={{ minWidth: '33.33%', maxWidth: '33.33%' }}
/>
<Text
type={'Heading1'}
text={'Skylink'}
style={{ minWidth: '33.33%', maxWidth: '33.33%' }}
/>
<Text
type={'Heading1'}
text={'Token'}
style={{ minWidth: '33.33%', maxWidth: '33.33%' }}
/>
</div>
<hr/>
<hr />
<div className={'ImportListOwner'}>
{
imports_array.map(data => {
return (
<div key={'import_' + key++}>
<Import data={data}/>
</div>
);
})
}
{imports_array.map((data) => {
return (
<div key={'import_' + key++}>
<Import data={data} />
</div>
);
})}
</div>
</div>
);

View File

@@ -1,228 +1,278 @@
import React from 'react'
import {connect} from 'react-redux';
import './SkynetImport.css'
import React from 'react';
import { connect } from 'react-redux';
import './SkynetImport.css';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import {displaySkynetImport} from '../../redux/actions/skynet_actions';
import ImportList from './ImportList/ImportList'
import { displaySkynetImport } from '../../redux/actions/skynet_actions';
import ImportList from './ImportList/ImportList';
import IPCContainer from '../IPCContainer/IPCContainer';
import {notifyApplicationBusy} from '../../redux/actions/common_actions';
import {
notifyError,
notifyInfo
} from '../../redux/actions/error_actions';
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
const Constants = require('../../constants');
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
AppBusy: state.common.AppBusy,
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch) => {
return {
displaySkynetImport: display => dispatch(displaySkynetImport(display)),
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
notifyError: msg => dispatch(notifyError(msg)),
displaySkynetImport: (display) => dispatch(displaySkynetImport(display)),
notifyApplicationBusy: (busy) =>
dispatch(notifyApplicationBusy(busy, true)),
notifyError: (msg) => dispatch(notifyError(msg)),
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(class SkynetImport extends IPCContainer {
export default connect(
mapStateToProps,
mapDispatchToProps
)(
class SkynetImport extends IPCContainer {
state = {
import_text: '',
imports_array: [],
second_stage: false,
};
state = {
import_text: '',
imports_array: [],
second_stage: false,
};
componentDidMount() {
this.setRequestHandler(
Constants.IPC_Import_Skylinks_Reply,
this.onImportSkylinksReply
);
}
componentDidMount() {
this.setRequestHandler(Constants.IPC_Import_Skylinks_Reply, this.onImportSkylinksReply);
}
componentWillUnmount() {
super.componentWillUnmount();
}
componentWillUnmount() {
super.componentWillUnmount();
}
displaySyntax = () => {
const msg =
'!alternate!To import Skylinks into the root directory, list each Skylink on a new line:\n' +
' AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA\n' +
' AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg\n' +
'\n' +
'To import Skylinks into new or existing directories, use the following syntax:\n' +
' directory="/my/sub/dir",skylink="AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA"\n' +
' directory="/my/sub/dir2",skylink="AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg"\n' +
'\n' +
'You can also specify a password if this in an encrypted Repertory Skylink:\n' +
' directory="/my/sub/dir",skylink="AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA",token="My Password"\n' +
' directory="/my/sub/dir",skylink="AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg",token="My Password"\n' +
'\n' +
'To import Skylinks using JSON syntax:\n' +
' [\n' +
' {\n' +
' "directory": "/",\n' +
' "skylink": "AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA",\n' +
' "token": "My Password"\n' +
' },\n' +
' {\n' +
' "directory": "/my/sub/dir",\n' +
' "skylink": "AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg",\n' +
' "token": "My Password"\n' +
' }\n' +
' ]';
this.props.notifyInfo('Import Syntax', msg);
};
displaySyntax = () => {
const msg = '!alternate!To import Skylinks into the root directory, list each Skylink on a new line:\n' +
' AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA\n' +
' AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg\n' +
'\n' +
'To import Skylinks into new or existing directories, use the following syntax:\n' +
' directory="/my/sub/dir",skylink="AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA"\n' +
' directory="/my/sub/dir2",skylink="AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg"\n' +
'\n' +
'You can also specify a password if this in an encrypted Repertory Skylink:\n' +
' directory="/my/sub/dir",skylink="AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA",token="My Password"\n' +
' directory="/my/sub/dir",skylink="AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg",token="My Password"\n' +
'\n' +
'To import Skylinks using JSON syntax:\n' +
' [\n' +
' {\n' +
' "directory": "/",\n' +
' "skylink": "AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA",\n' +
' "token": "My Password"\n' +
' },\n' +
' {\n' +
' "directory": "/my/sub/dir",\n' +
' "skylink": "AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg",\n' +
' "token": "My Password"\n' +
' }\n' +
' ]';
this.props.notifyInfo('Import Syntax', msg)
}
handleNavigation = () => {
if (this.state.second_stage) {
try {
this.props.notifyApplicationBusy(true);
this.sendRequest(Constants.IPC_Import_Skylinks, {
Version: this.props.version,
JsonArray: this.state.imports_array,
});
} catch (e) {
this.props.notifyApplicationBusy(false);
this.props.notifyError(e);
}
} else {
const items = this.state.import_text.split('\n');
let importsArray = [];
try {
for (let item of items) {
item = item.trim();
if (item.startsWith('[')) {
importsArray = JSON.parse(this.state.import_text.trim());
break;
} else if (item.indexOf('=') >= 0) {
const parts = item.split(',')
let importItem = {
directory: '/',
skylink: '',
token: '',
};
for (let part of parts) {
part = part.trim();
const pair = part.split('=');
if (pair.length !== 2) {
throw new Error('Invalid syntax for import: directory="",skylink="",token=""');
}
importItem = {
...importItem,
[pair[0].trim()]: pair[1].trim().replace(/"/g, ''),
handleNavigation = () => {
if (this.state.second_stage) {
try {
this.props.notifyApplicationBusy(true);
this.sendRequest(Constants.IPC_Import_Skylinks, {
Version: this.props.version,
JsonArray: this.state.imports_array,
});
} catch (e) {
this.props.notifyApplicationBusy(false);
this.props.notifyError(e);
}
} else {
const items = this.state.import_text.split('\n');
let importsArray = [];
try {
for (let item of items) {
item = item.trim();
if (item.startsWith('[')) {
importsArray = JSON.parse(this.state.import_text.trim());
break;
} else if (item.indexOf('=') >= 0) {
const parts = item.split(',');
let importItem = {
directory: '/',
skylink: '',
token: '',
};
for (let part of parts) {
part = part.trim();
const pair = part.split('=');
if (pair.length !== 2) {
throw new Error(
'Invalid syntax for import: directory="",skylink="",token=""'
);
}
importItem = {
...importItem,
[pair[0].trim()]: pair[1].trim().replace(/"/g, ''),
};
}
if (!importItem.skylink) {
throw new Error(
'Invalid syntax for import: directory="",skylink="",token=""'
);
}
importsArray.push(importItem);
} else if (item.length > 0) {
importsArray.push({
directory: '/',
skylink: item,
});
}
if (!importItem.skylink) {
throw new Error('Invalid syntax for import: directory="",skylink="",token=""');
}
importsArray.push(importItem);
} else if (item.length > 0) {
importsArray.push({
directory: '/',
skylink: item,
});
}
}
if (importsArray.length === 0) {
throw new Error('Nothing to import');
if (importsArray.length === 0) {
throw new Error('Nothing to import');
}
this.setState({
imports_array: importsArray,
second_stage: true,
});
} catch (e) {
this.props.notifyError(e);
}
this.setState({
imports_array: importsArray,
second_stage: true,
});
} catch (e) {
this.props.notifyError(e);
}
}
}
};
onImportSkylinksReply = (_, arg) => {
this.props.notifyApplicationBusy(false);
if (arg.data.Success) {
const failedImportsArray = this.state.imports_array.filter(i => {
return arg.data.Result.failed.includes(i.skylink);
});
const count = this.state.imports_array.length;
this.setState({
import_text: failedImportsArray.length > 0 ? JSON.stringify(failedImportsArray, null, 2) : '',
imports_array: [],
second_stage: false,
}, () => {
if (failedImportsArray.length > 0) {
this.props.notifyError(`Failed to import ${failedImportsArray.length} item(s)`);
} else {
this.props.notifyInfo('Import Result', `Successfully imported ${count} item(s)`);
}
});
} else {
this.props.notifyError(arg.data.Error);
}
};
onImportSkylinksReply = (_, arg) => {
this.props.notifyApplicationBusy(false);
if (arg.data.Success) {
const failedImportsArray = this.state.imports_array.filter((i) => {
return arg.data.Result.failed.includes(i.skylink);
});
const count = this.state.imports_array.length;
this.setState(
{
import_text:
failedImportsArray.length > 0
? JSON.stringify(failedImportsArray, null, 2)
: '',
imports_array: [],
second_stage: false,
},
() => {
if (failedImportsArray.length > 0) {
this.props.notifyError(
`Failed to import ${failedImportsArray.length} item(s)`
);
} else {
this.props.notifyInfo(
'Import Result',
`Successfully imported ${count} item(s)`
);
}
}
);
} else {
this.props.notifyError(arg.data.Error);
}
};
render() {
return this.props.AppBusy ? (<div/>) : (
<Box dxDark dxStyle={{
height: 'auto',
padding: 'var(--default_spacing)',
width: 'calc(100vw - (var(--default_spacing) * 4)'
}}>
<div
style={{
float: 'right',
margin: 0,
padding: 0,
marginTop: '-4px',
boxSizing: 'border-box',
display: 'block'
}}>
<a href={'#'}
onClick={() => this.props.displaySkynetImport(false)}
style={{cursor: 'pointer'}}>X</a>
</div>
<h1
className={'SkynetImportHeading'}>{this.state.second_stage ? 'Verify Imports' : 'Import List'}</h1>
{
this.state.second_stage ? (
<ImportList imports_array={this.state.imports_array}/>
render() {
return this.props.AppBusy ? (
<div />
) : (
<Box
dxDark
dxStyle={{
height: 'auto',
padding: 'var(--default_spacing)',
width: 'calc(100vw - (var(--default_spacing) * 4)',
}}
>
<div
style={{
float: 'right',
margin: 0,
padding: 0,
marginTop: '-4px',
boxSizing: 'border-box',
display: 'block',
}}
>
<a
href={'#'}
onClick={() => this.props.displaySkynetImport(false)}
style={{ cursor: 'pointer' }}
>
X
</a>
</div>
<h1 className={'SkynetImportHeading'}>
{this.state.second_stage ? 'Verify Imports' : 'Import List'}
</h1>
{this.state.second_stage ? (
<ImportList imports_array={this.state.imports_array} />
) : (
<textarea autoFocus={true}
className={'SkynetImportTextArea'}
onChange={e => this.setState({
import_text: e.target.value,
})}
value={this.state.import_text}
rows={10}/>
)
}
<div className={'SkynetImportButtons'}>
<Button
buttonStyles={{height: 'auto', marginTop: 'var(--default_spacing)', width: 'auto'}}
clicked={this.displaySyntax}>Import Syntax...</Button>
<div className={'SkynetActionButtons'}>
{
this.state.second_stage ?
<Button buttonStyles={{
<textarea
autoFocus={true}
className={'SkynetImportTextArea'}
onChange={(e) =>
this.setState({
import_text: e.target.value,
})
}
value={this.state.import_text}
rows={10}
/>
)}
<div className={'SkynetImportButtons'}>
<Button
buttonStyles={{
height: 'auto',
marginTop: 'var(--default_spacing)',
width: 'auto',
}}
clicked={this.displaySyntax}
>
Import Syntax...
</Button>
<div className={'SkynetActionButtons'}>
{this.state.second_stage ? (
<Button
buttonStyles={{
height: 'auto',
marginLeft: 'var(--default_spacing)',
marginTop: 'var(--default_spacing)',
width: 'auto',
}}
clicked={() =>
this.setState({
second_stage: false,
})
}
>
{'Back'}
</Button>
) : null}
<Button
buttonStyles={{
height: 'auto',
marginLeft: 'var(--default_spacing)',
marginTop: 'var(--default_spacing)',
width: 'auto'
}} clicked={() => this.setState({
second_stage: false,
})}>{'Back'}</Button> :
null
}
<Button buttonStyles={{
height: 'auto',
marginLeft: 'var(--default_spacing)',
marginTop: 'var(--default_spacing)',
width: 'auto'
}}
clicked={this.handleNavigation}>{this.state.second_stage ? 'Import' : 'Next'}</Button>
width: 'auto',
}}
clicked={this.handleNavigation}
>
{this.state.second_stage ? 'Import' : 'Next'}
</Button>
</div>
</div>
</div>
</Box>
);
</Box>
);
}
}
});
);

View File

@@ -1,7 +1,7 @@
import React, {Component} from 'react';
import React, { Component } from 'react';
import './Password.css';
import {faEye, faEyeSlash} from '@fortawesome/free-solid-svg-icons';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
export default class Password extends Component {
state = {
@@ -12,14 +12,14 @@ export default class Password extends Component {
};
componentDidMount() {
if (!this.props.value || (this.props.value.length === 0)) {
if (!this.props.value || this.props.value.length === 0) {
this.setState({
...this.state,
button_text: 'set',
password: '',
password2: '',
show_password: false,
})
});
} else {
this.setState({
...this.state,
@@ -27,7 +27,7 @@ export default class Password extends Component {
password: this.props.value,
password2: '',
show_password: false,
})
});
}
}
@@ -48,20 +48,26 @@ export default class Password extends Component {
this.props.changed(this.state.password);
this.setState({
...this.state,
button_text: this.state.password && this.state.password.length > 0 ? 'clear' : 'set',
button_text:
this.state.password && this.state.password.length > 0
? 'clear'
: 'set',
password2: '',
});
} else {
this.setState({
...this.state,
button_text: 'set',
password: '',
password2: '',
}, () => {
if (this.props.mismatchHandler) {
this.props.mismatchHandler();
this.setState(
{
...this.state,
button_text: 'set',
password: '',
password2: '',
},
() => {
if (this.props.mismatchHandler) {
this.props.mismatchHandler();
}
}
});
);
}
break;
@@ -79,7 +85,7 @@ export default class Password extends Component {
}
};
handlePasswordChanged = e => {
handlePasswordChanged = (e) => {
if (this.state.button_text === 'set') {
this.setState({
...this.state,
@@ -93,8 +99,11 @@ export default class Password extends Component {
}
};
handlePasswordKeyUp = e => {
if ((e.keyCode === 13) && ((this.state.button_text === 'confirm') || (this.state.button_text === 'set'))) {
handlePasswordKeyUp = (e) => {
if (
e.keyCode === 13 &&
(this.state.button_text === 'confirm' || this.state.button_text === 'set')
) {
this.handleActionClick();
}
};
@@ -108,28 +117,41 @@ export default class Password extends Component {
render() {
return (
<div className={'PasswordOwner'} style={{...this.props.style}}>
{
this.props.readOnly ? null : <a href={'#'}
className={'PasswordLink'}
onClick={this.handleActionClick}>
<div className={'PasswordOwner'} style={{ ...this.props.style }}>
{this.props.readOnly ? null : (
<a
href={'#'}
className={'PasswordLink'}
onClick={this.handleActionClick}
>
<u>{this.state.button_text}</u>
</a>
}
<input autoFocus={this.props.autoFocus}
readOnly={this.props.readOnly}
className={'PasswordInput'}
disabled={this.props.readOnly || (this.state.button_text === 'clear')}
onChange={this.handlePasswordChanged}
onKeyUp={this.handlePasswordKeyUp}
type={this.state.show_password ? 'text' : 'password'}
value={(this.state.button_text === 'confirm') ? this.state.password2 : this.state.password}/>
<a href={'#'}
className={'PasswordShowHide'}
onClick={this.handleShowHideClick}>
<FontAwesomeIcon icon={this.state.show_password ? faEye : faEyeSlash} fixedWidth/>
)}
<input
autoFocus={this.props.autoFocus}
readOnly={this.props.readOnly}
className={'PasswordInput'}
disabled={this.props.readOnly || this.state.button_text === 'clear'}
onChange={this.handlePasswordChanged}
onKeyUp={this.handlePasswordKeyUp}
type={this.state.show_password ? 'text' : 'password'}
value={
this.state.button_text === 'confirm'
? this.state.password2
: this.state.password
}
/>
<a
href={'#'}
className={'PasswordShowHide'}
onClick={this.handleShowHideClick}
>
<FontAwesomeIcon
icon={this.state.show_password ? faEye : faEyeSlash}
fixedWidth
/>
</a>
</div>
);
}
};
}