Partial export processing
This commit is contained in:
@@ -20,16 +20,46 @@ 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!')) {
|
|
||||||
classes.push('Alternate');
|
let changed = true;
|
||||||
msg = props.InfoMessage.message.substr('!alternate!'.length)
|
let copyable = false;
|
||||||
|
while (changed) {
|
||||||
|
changed = false;
|
||||||
|
if (msg.startsWith('!alternate!')) {
|
||||||
|
classes.push('Alternate');
|
||||||
|
msg = msg.substr('!alternate!'.length);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (msg.startsWith('!copyable!')) {
|
||||||
|
classes.push('Copyable');
|
||||||
|
msg = msg.substr('!copyable!'.length);
|
||||||
|
copyable = changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollToTop = textArea => {
|
||||||
|
if (!textArea.firstClick) {
|
||||||
|
textArea.firstClick = true;
|
||||||
|
textArea.scrollTop = 0;
|
||||||
|
textArea.setSelectionRange(0, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||||
<h1 className={'InfoDetailsHeading'}>{props.InfoMessage.title}</h1>
|
<h1 className={'InfoDetailsHeading'}>{props.InfoMessage.title}</h1>
|
||||||
<div className={classes.join(' ')}>
|
<div className={classes.join(' ')}>
|
||||||
<p style={{textAlign: 'left'}}>{msg}</p>
|
{
|
||||||
|
copyable ? (
|
||||||
|
<textarea autoFocus
|
||||||
|
rows={9}
|
||||||
|
value={msg}
|
||||||
|
className={'SkynetImportTextArea'}
|
||||||
|
onClick={e => scrollToTop(e.target)}/>
|
||||||
|
) : (
|
||||||
|
<p style={{textAlign: 'left'}}>{msg}</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<Button clicked={props.dismissInfo}>Dismiss</Button>
|
<Button clicked={props.dismissInfo}>Dismiss</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import CheckboxTree from 'react-checkbox-tree';
|
|||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||||
import {notifyApplicationBusy} from '../../redux/actions/common_actions';
|
import {notifyApplicationBusy} from '../../redux/actions/common_actions';
|
||||||
import {notifyError} from '../../redux/actions/error_actions';
|
import {notifyError, notifyInfo} from '../../redux/actions/error_actions';
|
||||||
import Box from '../../components/UI/Box/Box';
|
import Box from '../../components/UI/Box/Box';
|
||||||
import {displaySkynetExport} from '../../redux/actions/skynet_actions';
|
import {displaySkynetExport} from '../../redux/actions/skynet_actions';
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||||
@@ -29,6 +29,7 @@ const mapDispatchToProps = dispatch => {
|
|||||||
displaySkynetExport: display => dispatch(displaySkynetExport(display)),
|
displaySkynetExport: display => dispatch(displaySkynetExport(display)),
|
||||||
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
|
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
|
||||||
notifyError: msg => dispatch(notifyError(msg)),
|
notifyError: msg => dispatch(notifyError(msg)),
|
||||||
|
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCCon
|
|||||||
const treeItem = {
|
const treeItem = {
|
||||||
label: item.name,
|
label: item.name,
|
||||||
path: item.path,
|
path: item.path,
|
||||||
value: item.name === '/' ? 0 : JSON.stringify(item),
|
value: item.name === '/' ? 0 : item.path ? item.path : JSON.stringify(item),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (item.directory) {
|
if (item.directory) {
|
||||||
@@ -80,7 +81,11 @@ export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCCon
|
|||||||
|
|
||||||
handleNavigation = () => {
|
handleNavigation = () => {
|
||||||
if (this.state.second_stage) {
|
if (this.state.second_stage) {
|
||||||
|
this.props.notifyApplicationBusy(true);
|
||||||
|
this.sendRequest(Constants.IPC_Export_Skylinks, {
|
||||||
|
Version: this.props.version,
|
||||||
|
Paths: this.state.checked,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
if (this.state.checked.length === 0) {
|
if (this.state.checked.length === 0) {
|
||||||
this.props.notifyError('No files have been checked');
|
this.props.notifyError('No files have been checked');
|
||||||
@@ -93,6 +98,21 @@ export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
onExportSkylinksReply = (_, arg) => {
|
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) => {
|
onGrabSkynetTreeReply = (_, arg) => {
|
||||||
@@ -133,47 +153,59 @@ export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCCon
|
|||||||
onClick={() => this.props.displaySkynetExport(false)}
|
onClick={() => this.props.displaySkynetExport(false)}
|
||||||
style={{cursor: 'pointer'}}>X</a>
|
style={{cursor: 'pointer'}}>X</a>
|
||||||
</div>
|
</div>
|
||||||
<h1 className={'SkynetExportHeading'}>{'Export Files'}</h1>
|
<h1
|
||||||
|
className={'SkynetExportHeading'}>{this.state.second_stage ? 'Verify Exports' : 'Export Files'}</h1>
|
||||||
<div style={{overflowX: 'auto', overflowY: 'auto', height: 'calc(90vh - 80px)'}}>
|
<div style={{overflowX: 'auto', overflowY: 'auto', height: 'calc(90vh - 80px)'}}>
|
||||||
{
|
{
|
||||||
this.state.second_stage ? (<div/>) : (
|
this.state.second_stage ?
|
||||||
<CheckboxTree checked={this.state.checked}
|
this.state.checked.map(path => {
|
||||||
expanded={this.state.expanded}
|
return (
|
||||||
expandOnClick
|
<input readOnly
|
||||||
showExpandAll
|
className={'ConfigurationItemInput'}
|
||||||
icons={{
|
key={path}
|
||||||
check: <FontAwesomeIcon icon={faCheckSquare} fixedWidth
|
style={{width: '100%', marginBottom: 'var(--default_spacing)'}}
|
||||||
style={{padding: 0, margin: 0}}/>,
|
type={'text'}
|
||||||
uncheck: <FontAwesomeIcon icon={faSquare} fixedWidth
|
value={path}/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: (
|
||||||
|
<CheckboxTree checked={this.state.checked}
|
||||||
|
expanded={this.state.expanded}
|
||||||
|
expandOnClick
|
||||||
|
showExpandAll
|
||||||
|
icons={{
|
||||||
|
check: <FontAwesomeIcon icon={faCheckSquare} fixedWidth
|
||||||
style={{padding: 0, margin: 0}}/>,
|
style={{padding: 0, margin: 0}}/>,
|
||||||
halfCheck: <FontAwesomeIcon icon={faHSquare} fixedWidth
|
uncheck: <FontAwesomeIcon icon={faSquare} fixedWidth
|
||||||
style={{padding: 0, margin: 0}}/>,
|
style={{padding: 0, margin: 0}}/>,
|
||||||
expandClose: <FontAwesomeIcon icon={faChevronRight} fixedWidth
|
halfCheck: <FontAwesomeIcon icon={faHSquare} fixedWidth
|
||||||
style={{padding: 0, margin: 0}}/>,
|
style={{padding: 0, margin: 0}}/>,
|
||||||
expandOpen: <FontAwesomeIcon icon={faChevronDown} fixedWidth
|
expandClose: <FontAwesomeIcon icon={faChevronRight} fixedWidth
|
||||||
style={{padding: 0, margin: 0}}/>,
|
style={{padding: 0, margin: 0}}/>,
|
||||||
expandAll: <FontAwesomeIcon icon={faPlusSquare} fixedWidth
|
expandOpen: <FontAwesomeIcon icon={faChevronDown} fixedWidth
|
||||||
style={{padding: 0, margin: 0}}/>,
|
style={{padding: 0, margin: 0}}/>,
|
||||||
collapseAll: <FontAwesomeIcon icon={faMinusSquare} fixedWidth
|
expandAll: <FontAwesomeIcon icon={faPlusSquare} fixedWidth
|
||||||
style={{padding: 0, margin: 0}}/>,
|
style={{padding: 0, margin: 0}}/>,
|
||||||
parentClose: <FontAwesomeIcon icon={faFolder}
|
collapseAll: <FontAwesomeIcon icon={faMinusSquare} fixedWidth
|
||||||
fixedWidth
|
style={{padding: 0, margin: 0}}/>,
|
||||||
color={'var(--heading_text_color)'}
|
parentClose: <FontAwesomeIcon icon={faFolder}
|
||||||
style={{padding: 0, margin: 0}}/>,
|
fixedWidth
|
||||||
parentOpen: <FontAwesomeIcon icon={faFolderOpen}
|
color={'var(--heading_text_color)'}
|
||||||
fixedWidth
|
style={{padding: 0, margin: 0}}/>,
|
||||||
color={'var(--heading_text_color)'}
|
parentOpen: <FontAwesomeIcon icon={faFolderOpen}
|
||||||
style={{padding: 0, margin: 0}}/>,
|
fixedWidth
|
||||||
leaf: <FontAwesomeIcon icon={faFile}
|
color={'var(--heading_text_color)'}
|
||||||
fixedWidth
|
style={{padding: 0, margin: 0}}/>,
|
||||||
color={'var(--text_color)'}
|
leaf: <FontAwesomeIcon icon={faFile}
|
||||||
style={{padding: 0, margin: 0}}/>
|
fixedWidth
|
||||||
}}
|
color={'var(--text_color)'}
|
||||||
nodes={this.state.nodes}
|
style={{padding: 0, margin: 0}}/>
|
||||||
onClick={clicked => this.setState({clicked})}
|
}}
|
||||||
onCheck={checked => this.setState({checked})}
|
nodes={this.state.nodes}
|
||||||
onExpand={expanded => this.setState({expanded})}/>
|
onClick={clicked => this.setState({clicked})}
|
||||||
)
|
onCheck={checked => this.setState({checked})}
|
||||||
|
onExpand={expanded => this.setState({expanded})}/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div style={{display: 'flex', justifyContent: 'flex-end'}}>
|
<div style={{display: 'flex', justifyContent: 'flex-end'}}>
|
||||||
|
|||||||
@@ -597,6 +597,48 @@ module.exports.executeMount = (version, provider, remote, location, exitCallback
|
|||||||
|
|
||||||
module.exports.exportAllSkylinks = _exportAllSkylinks;
|
module.exports.exportAllSkylinks = _exportAllSkylinks;
|
||||||
|
|
||||||
|
module.exports.exportSkylinks = (version, paths) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const repertoryExec = _getRepertoryExec(version);
|
||||||
|
const processOptions = {
|
||||||
|
cwd: repertoryExec.working,
|
||||||
|
detached: true,
|
||||||
|
shell: false,
|
||||||
|
windowsHide: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const args = _getDefaultRepertoryArgs('Skynet');
|
||||||
|
args.push('-ex');
|
||||||
|
args.push(paths.join(','));
|
||||||
|
|
||||||
|
let result = '';
|
||||||
|
const process = new spawn(repertoryExec.cmd, args, processOptions);
|
||||||
|
|
||||||
|
process.on('error', (err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.stdout.on('data', (d) => {
|
||||||
|
result += d;
|
||||||
|
});
|
||||||
|
|
||||||
|
process.stderr.on('data', (d) => {
|
||||||
|
result += d;
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('exit', code => {
|
||||||
|
if (code === 0) {
|
||||||
|
result = result.substr(result.indexOf('{'));
|
||||||
|
resolve(JSON.parse(result));
|
||||||
|
} else {
|
||||||
|
reject(new Error('Failed to import: ' + code + ':' + result));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
process.unref();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.getConfig = (version, provider, remote) => {
|
module.exports.getConfig = (version, provider, remote) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const repertoryExec = _getRepertoryExec(version);
|
const repertoryExec = _getRepertoryExec(version);
|
||||||
|
|||||||
@@ -2,16 +2,16 @@ const Constants = require('../../constants');
|
|||||||
const helpers = require('../../helpers');
|
const helpers = require('../../helpers');
|
||||||
|
|
||||||
const addListeners = (ipcMain, {standardIPCReply}) => {
|
const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||||
ipcMain.on(Constants.IPC_Import_Skylinks, (event, data) => {
|
ipcMain.on(Constants.IPC_Export_Skylinks, (event, data) => {
|
||||||
helpers
|
helpers
|
||||||
.importSkylinks(data.Version, data.JsonArray)
|
.exportSkylinks(data.Version, data.Paths)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, {
|
standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {
|
||||||
Result: result,
|
Result: result,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, {}, error);
|
standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {}, error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,6 +27,19 @@ const addListeners = (ipcMain, {standardIPCReply}) => {
|
|||||||
standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, {}, error);
|
standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, {}, error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Import_Skylinks, (event, data) => {
|
||||||
|
helpers
|
||||||
|
.importSkylinks(data.Version, data.JsonArray)
|
||||||
|
.then(result => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, {
|
||||||
|
Result: result,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, {}, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
Reference in New Issue
Block a user