Partial import processing

This commit is contained in:
2020-06-15 12:57:00 -05:00
parent 550e936baa
commit f29ecf5d5d
3 changed files with 111 additions and 47 deletions

View File

@@ -61,9 +61,9 @@ class App extends IPCContainer {
(prevProps.ReleaseVersion !== this.props.ReleaseVersion) || (prevProps.ReleaseVersion !== this.props.ReleaseVersion) ||
(prevProps.VersionLookup !== this.props.VersionLookup)) { (prevProps.VersionLookup !== this.props.VersionLookup)) {
this.props.saveState(); this.props.saveState();
} else if (Object.keys(this.props.ProviderState).filter(k=> { } else if (Object.keys(this.props.ProviderState).filter(k => {
return this.props.ProviderState[k] !== prevProps.ProviderState[k]; return this.props.ProviderState[k] !== prevProps.ProviderState[k];
}).length > 0) { }).length > 0) {
this.props.saveState(); this.props.saveState();
} }
} }
@@ -105,7 +105,7 @@ class App extends IPCContainer {
!missingDependencies && !missingDependencies &&
!this.props.InstallActive; !this.props.InstallActive;
const remoteSupported = this.props.LocationsLookup[selectedVersion] && const remoteSupported = this.props.LocationsLookup[selectedVersion] &&
this.props.LocationsLookup[selectedVersion].supports_remote; this.props.LocationsLookup[selectedVersion].supports_remote;
const gooboxS3Supported = this.props.LocationsLookup[selectedVersion] && const gooboxS3Supported = this.props.LocationsLookup[selectedVersion] &&
@@ -155,23 +155,24 @@ class App extends IPCContainer {
const showSkynetImport = !showConfig && const showSkynetImport = !showConfig &&
!showDependencies && !showDependencies &&
!this.props.DownloadActive && !this.props.DownloadActive &&
!this.props.DisplayError &&
!this.props.DisplayInfo &&
!showNewReleases && !showNewReleases &&
!this.props.RebootRequired && !this.props.RebootRequired &&
!this.props.DisplaySelectAppPlatform && !this.props.DisplaySelectAppPlatform &&
!showUpgrade && !showUpgrade &&
this.props.DisplayImport; this.props.DisplayImport;
const configDisplay = createModalConditionally(showConfig, <Configuration version={selectedVersion} remoteSupported={remoteSupported} />); const configDisplay = createModalConditionally(showConfig, <Configuration version={selectedVersion}
remoteSupported={remoteSupported}/>);
const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, <YesNo/>); const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, <YesNo/>);
const dependencyDisplay = createModalConditionally(showDependencies, <DependencyList/>, false, this.props.InstallActive); const dependencyDisplay = createModalConditionally(showDependencies,
const downloadDisplay = createModalConditionally(this.props.DownloadActive, <DownloadProgress />, false, true); <DependencyList/>, false, this.props.InstallActive);
const downloadDisplay = createModalConditionally(this.props.DownloadActive, <DownloadProgress/>, false, true);
const errorDisplay = createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true); const errorDisplay = createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
const infoDisplay = createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true); const infoDisplay = createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true);
const newReleasesDisplay = createModalConditionally(showNewReleases, <NewReleases/>); const newReleasesDisplay = createModalConditionally(showNewReleases, <NewReleases/>);
const rebootDisplay = createModalConditionally(this.props.RebootRequired, <Reboot />); const rebootDisplay = createModalConditionally(this.props.RebootRequired, <Reboot/>);
const selectAppPlatformDisplay = createModalConditionally(this.props.DisplaySelectAppPlatform, <SelectAppPlatform/>); const selectAppPlatformDisplay = createModalConditionally(this.props.DisplaySelectAppPlatform,
<SelectAppPlatform/>);
const upgradeDisplay = createModalConditionally(showUpgrade, <UpgradeUI/>); const upgradeDisplay = createModalConditionally(showUpgrade, <UpgradeUI/>);
const importDisplay = createModalConditionally(showSkynetImport, <SkynetImport/>); const importDisplay = createModalConditionally(showSkynetImport, <SkynetImport/>);
@@ -233,7 +234,7 @@ class App extends IPCContainer {
col={dimensions => dimensions.columns - 6} col={dimensions => dimensions.columns - 6}
colSpan={5} colSpan={5}
row={1} row={1}
rowSpan={remain=>remain - 1}/> rowSpan={remain => remain - 1}/>
</Grid> </Grid>
</Box> </Box>
</div> </div>
@@ -294,7 +295,7 @@ const mapStateToProps = state => {
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
displaySelectAppPlatform: display => dispatch(displaySelectAppPlatform(display)), displaySelectAppPlatform: display => dispatch(displaySelectAppPlatform(display)),
loadReleases: ()=> dispatch(loadReleases()), loadReleases: () => dispatch(loadReleases()),
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)), notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
saveState: () => dispatch(saveState()), saveState: () => dispatch(saveState()),
setDismissNewReleasesAvailable: dismiss => dispatch(setDismissNewReleasesAvailable), setDismissNewReleasesAvailable: dismiss => dispatch(setDismissNewReleasesAvailable),

View File

@@ -20,7 +20,7 @@ const mapDispatchToProps = dispatch => {
export default connect(mapStateToProps, mapDispatchToProps)(props => { export default connect(mapStateToProps, mapDispatchToProps)(props => {
let msg = props.InfoMessage.message; let msg = props.InfoMessage.message;
const classes = ['InfoDetailsContent']; const classes = ['InfoDetailsContent'];
if (props.InfoMessage.message.startsWith("!alternate!")) { if (props.InfoMessage.message.startsWith('!alternate!')) {
classes.push('Alternate'); classes.push('Alternate');
msg = props.InfoMessage.message.substr('!alternate!'.length) msg = props.InfoMessage.message.substr('!alternate!'.length)
} }

View File

@@ -5,12 +5,16 @@ import './SkynetImport.css'
import Box from '../../components/UI/Box/Box'; import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button'; import Button from '../../components/UI/Button/Button';
import {displaySkynetImport} from '../../redux/actions/skynet_actions'; import {displaySkynetImport} from '../../redux/actions/skynet_actions';
import {notifyInfo} from '../../redux/actions/error_actions'; import {
notifyError,
notifyInfo
} from '../../redux/actions/error_actions';
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
displaySkynetImport: display => dispatch(displaySkynetImport(display)), displaySkynetImport: display => dispatch(displaySkynetImport(display)),
notifyInfo: msg => dispatch(notifyInfo("Import Syntax", msg)), notifyInfo: msg => dispatch(notifyInfo('Import Syntax', msg)),
notifyError: msg => dispatch(notifyError(msg)),
} }
}; };
@@ -21,40 +25,93 @@ export default connect(null, mapDispatchToProps)(class extends Component {
}; };
displaySyntax = () => { displaySyntax = () => {
const msg = "!alternate!To import Skylinks into the root directory, list each Skylink on a new line:\n" + const msg = '!alternate!To import Skylinks into the root directory, list each Skylink on a new line:\n' +
" AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA\n" + ' AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA\n' +
" AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg\n" + ' AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg\n' +
"\n" + '\n' +
"To import Skylinks to new or existing directories, use the following syntax:\n" + 'To import Skylinks to new or existing directories, use the following syntax:\n' +
" directory=\"/my/sub/dir\",skylink=\"AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA\"\n" + ' directory="/my/sub/dir",skylink="AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA"\n' +
" directory=\"/my/sub/dir2\",skylink=\"AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg\"\n" + ' directory="/my/sub/dir2",skylink="AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg"\n' +
"\n" + '\n' +
"You can also specify a password if this in an encrypted Repertory Skylink:\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="AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA",token="My Password"\n' +
" directory=\"/my/sub/dir\",skylink=\"AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg\",token=\"My Password\"\n" + ' directory="/my/sub/dir",skylink="AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg",token="My Password"\n' +
"\n" + '\n' +
"To import JSON Skylinks, use the following syntax:\n" + 'To import JSON Skylinks, use the following syntax:\n' +
" [\n" + ' [\n' +
" {\n" + ' {\n' +
" \"directory\": \"/\",\n" + ' "directory": "/",\n' +
" \"skylink\": \"AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA\",\n" + ' "skylink": "AACeCiD6WQG6DzDcCdIu3cFPSxMUMoQPx46NYSyijNMKUA",\n' +
" \"token\": \"My Password\"\n" + ' "token": "My Password"\n' +
" },\n" + ' },\n' +
" {\n" + ' {\n' +
" \"directory\": \"/my/sub/dir\",\n" + ' "directory": "/my/sub/dir",\n' +
" \"skylink\": \"AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg\",\n" + ' "skylink": "AACyjmDGoHqY7mTaxi-rkpnKUJGZK1B4UhrF74Nv6tY6Cg",\n' +
" \"token\": \"My Password\"\n" + ' "token": "My Password"\n' +
" }\n" + ' }\n' +
" ]"; ' ]';
this.props.notifyInfo(msg) this.props.notifyInfo(msg)
} }
processNext = () => {
const items = this.state.import_list.split('\n');
let jsonItems = [];
try {
for (let item of items) {
item = item.trim();
if (item.startsWith('[')) {
jsonItems = JSON.parse(this.state.import_list.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=""');
}
jsonItems.push(importItem);
} else if (item.length > 0) {
jsonItems.push({
directory: '/',
skylink: item,
});
}
}
if (jsonItems.length === 0) {
throw new Error('Nothing to import');
}
console.log(jsonItems);
} catch (e) {
this.props.notifyError(e);
}
}
render() { render() {
return ( return (
<Box dxDark dxStyle={{height: 'auto', padding: 'var(--default_spacing)', width: 'calc(100vw - (var(--default_spacing) * 4)'}}> <Box dxDark dxStyle={{
<div style={{float: 'right', margin: 0, padding: 0, marginTop: '-4px', boxSizing: 'border-box', display: 'block'}}> 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={'#'} <a href={'#'}
onClick={()=>this.props.displaySkynetImport(false)} onClick={() => this.props.displaySkynetImport(false)}
style={{cursor: 'pointer'}}>X</a> style={{cursor: 'pointer'}}>X</a>
</div> </div>
<h1 className={'SkynetImportHeading'}>Import List</h1> <h1 className={'SkynetImportHeading'}>Import List</h1>
@@ -65,11 +122,17 @@ export default connect(null, mapDispatchToProps)(class extends Component {
import_list: e.target.value, import_list: e.target.value,
})} })}
value={this.state.import_list} value={this.state.import_list}
rows={10} /> rows={10}/>
<div className={'SkynetImportButtons'}> <div className={'SkynetImportButtons'}>
<Button buttonStyles={{height: 'auto', marginTop: 'var(--default_spacing)', width: 'auto'}} clicked={this.displaySyntax}>Import Syntax...</Button> <Button buttonStyles={{height: 'auto', marginTop: 'var(--default_spacing)', width: 'auto'}}
<Button buttonStyles={{height: 'auto', marginLeft: 'var(--default_spacing)', marginTop: 'var(--default_spacing)', width: 'auto'}}>Next</Button> clicked={this.displaySyntax}>Import Syntax...</Button>
<Button buttonStyles={{
height: 'auto',
marginLeft: 'var(--default_spacing)',
marginTop: 'var(--default_spacing)',
width: 'auto'
}} clicked={this.processNext}>Next</Button>
</div> </div>
</Box> </Box>
); );