278 lines
9.2 KiB
JavaScript
278 lines
9.2 KiB
JavaScript
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 IPCContainer from '../IPCContainer/IPCContainer';
|
|
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
|
|
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
|
|
import { promptLocationAndReadFile } from '../../utils';
|
|
|
|
const Constants = require('../../constants');
|
|
|
|
const mapStateToProps = (state) => {
|
|
return {
|
|
AppBusy: state.common.AppBusy,
|
|
};
|
|
};
|
|
|
|
const mapDispatchToProps = (dispatch) => {
|
|
return {
|
|
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 {
|
|
state = {
|
|
import_text: '',
|
|
imports_array: [],
|
|
second_stage: false,
|
|
};
|
|
|
|
componentDidMount() {
|
|
this.setRequestHandler(Constants.IPC_Import_Skylinks_Reply, this.onImportSkylinksReply);
|
|
}
|
|
|
|
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);
|
|
};
|
|
|
|
handleLoadFile = () => {
|
|
const data = promptLocationAndReadFile(this.props.notifyError);
|
|
if (data) {
|
|
this.setState({ import_text: data });
|
|
}
|
|
};
|
|
|
|
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 (importsArray.length === 0) {
|
|
throw new Error('Nothing to import');
|
|
}
|
|
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);
|
|
}
|
|
};
|
|
|
|
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={{
|
|
height: 'auto',
|
|
marginLeft: 'var(--default_spacing)',
|
|
marginTop: 'var(--default_spacing)',
|
|
width: 'auto',
|
|
}}
|
|
clicked={() =>
|
|
this.setState({
|
|
second_stage: false,
|
|
})
|
|
}>
|
|
{'Back'}
|
|
</Button>
|
|
) : null}
|
|
{!this.state.second_stage ? (
|
|
<Button
|
|
buttonStyles={{
|
|
height: 'auto',
|
|
marginLeft: 'var(--default_spacing)',
|
|
marginTop: 'var(--default_spacing)',
|
|
width: 'auto',
|
|
}}
|
|
clicked={this.handleLoadFile}>
|
|
{'Import File...'}
|
|
</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>
|
|
</div>
|
|
</div>
|
|
</Box>
|
|
);
|
|
}
|
|
}
|
|
);
|