This repository has been archived on 2025-09-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
repertory-ui/src/containers/SkynetImport/SkynetImport.js
2021-08-05 13:41:51 -05:00

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>
);
}
}
);