diff --git a/public/electron.js b/public/electron.js index fa5279b..9e2b41e 100644 --- a/public/electron.js +++ b/public/electron.js @@ -33,6 +33,7 @@ const DependencyIPC = require('../src/renderer/ipc/DependencyIPC'); const DownloadIPC = require('../src/renderer/ipc/DownloadIPC'); const FilesystemIPC = require('../src/renderer/ipc/FilesystemIPC'); const MountsIPC = require('../src/renderer/ipc/MountsIPC'); +const PinnedIPC = require('../src/renderer/ipc/PinnedIPC'); const PlatformIPC = require('../src/renderer/ipc/PlatformIPC'); const ReleaseIPC = require('../src/renderer/ipc/ReleaseIPC'); const SkynetIPC = require('../src/renderer/ipc/SkynetIPC'); @@ -330,6 +331,7 @@ DependencyIPC.addListeners(ipcMain, AppFunctions); DownloadIPC.addListeners(ipcMain, AppFunctions); FilesystemIPC.addListeners(ipcMain, AppFunctions); MountsIPC.addListeners(ipcMain, AppFunctions); +PinnedIPC.addListeners(ipcMain, AppFunctions); PlatformIPC.addListeners(ipcMain, AppFunctions); ReleaseIPC.addListeners(ipcMain, AppFunctions); SkynetIPC.addListeners(ipcMain, AppFunctions); diff --git a/src/App.js b/src/App.js index 784dd91..832672a 100644 --- a/src/App.js +++ b/src/App.js @@ -181,7 +181,8 @@ class App extends IPCContainer { version={selectedVersion} s3Supported={s3Supported} remoteSupported={remoteSupported}/>); - const pinnedManagerDisplay = createModalConditionally(showPinnedManager, ) + const pinnedManagerDisplay = createModalConditionally(showPinnedManager, ) const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, ); const dependencyDisplay = createModalConditionally(showDependencies, , false, this.props.InstallActive); diff --git a/src/constants.js b/src/constants.js index f66ba3e..8c45161 100644 --- a/src/constants.js +++ b/src/constants.js @@ -122,6 +122,15 @@ exports.IPC_Get_Config_Reply = 'get_config_reply'; exports.IPC_Get_Config_Template = 'get_config_template'; exports.IPC_Get_Config_Template_Reply = 'get_config_template_reply'; +exports.IPC_Get_Directory_Items = 'get_directory_items'; +exports.IPC_Get_Directory_Items_Reply = 'get_directory_items_reply'; + +exports.IPC_Get_Pinned_Files = 'get_pinned_files'; +exports.IPC_Get_Pinned_Files_Reply = 'get_pinned_files_reply'; + +exports.IPC_Get_Pinned_Files_Status = 'get_pinned_files_status'; +exports.IPC_Get_Pinned_Files_Status_Reply = 'get_pinned_files_status_reply'; + exports.IPC_Get_Platform = 'get_platform'; exports.IPC_Get_Platform_Reply = 'get_platform_reply'; @@ -150,6 +159,8 @@ exports.IPC_Reboot_System = 'reboot_system'; exports.IPC_Save_State = 'save_state'; +exports.IPC_Set_Pinned = 'set_pinned'; + exports.IPC_Show_Window = 'show_window'; exports.IPC_Set_Config_Values = 'set_config_values'; diff --git a/src/containers/PinnedManager/PinnedManager.css b/src/containers/PinnedManager/PinnedManager.css index e69de29..8ef8396 100644 --- a/src/containers/PinnedManager/PinnedManager.css +++ b/src/containers/PinnedManager/PinnedManager.css @@ -0,0 +1,17 @@ +.PinnedManagerActiveDirectory { + margin-top: var(--default_spacing); + margin-bottom: var(--default_spacing); + padding: 2px; + width: calc(100% - 4px); + text-align: left; + border-radius: var(--border_radius); + background: var(--control_background); +} + +.PinnedManagerItems { + padding: var(--default_spacing); + overflow-x: auto; + overflow-y: auto; + border-radius: var(--border_radius); + background: var(--control_background); +} diff --git a/src/containers/PinnedManager/PinnedManager.js b/src/containers/PinnedManager/PinnedManager.js index 90491e4..27138d1 100644 --- a/src/containers/PinnedManager/PinnedManager.js +++ b/src/containers/PinnedManager/PinnedManager.js @@ -7,13 +7,19 @@ 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 { - faCheckSquare, faChevronDown, - faChevronRight, faFile, faFolder, faFolderOpen, - faHSquare, faMinusSquare, faPlusSquare, - faSquare -} from '@fortawesome/free-solid-svg-icons'; +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 => { + return { + DisplayConfiguration: state.mounts.DisplayConfiguration, + DisplayRemoteConfiguration: state.mounts.DisplayRemoteConfiguration, + DisplayS3Configuration: state.mounts.DisplayS3Configuration, + } +}; const mapDispatchToProps = dispatch => { return { @@ -24,20 +30,115 @@ const mapDispatchToProps = dispatch => { } }; -export default connect(null, mapDispatchToProps)(class extends IPCContainer { +export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCContainer { state = { active_directory: '/', items: [], + previous_directory: '', } 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, false, () => { + this.props.displayPinnedManager(false); + }); + } + } + + createDirectory = (name, path, idx, total, item_idx) => { + const style = {} + if (item_idx + 1 !== total) { + style.marginBottom = '4px'; + } + return ( +
+ +
+ ); + } + + createFile = (name, pinned, idx, total, item_idx) => { + const style = {textAlign: 'left'} + if (item_idx + 1 !== total) { + style.marginBottom = '2px'; + } + return ( +
+ { + const items = JSON.parse(JSON.stringify(this.state.items)); + 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: items[item_idx].path, + Pinned: items[item_idx].meta.pinned, + }); + }); + }} + label={name}/> +
+ ); + } + render() { + let idx = 0; return ( X

{'Pinned File Manager'}

+

{this.state.active_directory}

- + { + 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.meta.pinned, idx++, this.state.items.length, k); + }) + }
) diff --git a/src/helpers.js b/src/helpers.js index 5068396..95f658e 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -840,6 +840,89 @@ module.exports.grabSkynetFileTree = version => { }); }; +module.exports.grabDirectoryItems = (path, version, provider, remote, s3) => { + return new Promise((resolve, reject) => { + const repertoryExec = _getRepertoryExec(version); + const processOptions = { + cwd: repertoryExec.working, + detached: true, + shell: false, + windowsHide: true, + }; + + const args = _getDefaultRepertoryArgs(provider, remote, s3); + args.push('-gdi'); + args.push(path); + + 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.setPinned = (path, pinned, version, provider, remote, s3) => { + return new Promise((resolve, reject) => { + const repertoryExec = _getRepertoryExec(version); + const processOptions = { + cwd: repertoryExec.working, + detached: true, + shell: false, + windowsHide: true, + }; + + const args = _getDefaultRepertoryArgs(provider, remote, s3); + args.push(pinned ? '-pf' : '-uf'); + args.push(path); + + 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) { + resolve(JSON.parse(result).success); + } else { + reject(new Error('Failed to import: ' + code + ':' + result)); + } + }); + + process.unref(); + }); +}; + module.exports.importSkylinks = (version, jsonArray) => { return new Promise((resolve, reject) => { const repertoryExec = _getRepertoryExec(version); diff --git a/src/renderer/ipc/PinnedIPC.js b/src/renderer/ipc/PinnedIPC.js new file mode 100644 index 0000000..2cc26d7 --- /dev/null +++ b/src/renderer/ipc/PinnedIPC.js @@ -0,0 +1,49 @@ +const Constants = require('../../constants'); +const helpers = require('../../helpers'); + +const addListeners = (ipcMain, {standardIPCReply}) => { + ipcMain.on(Constants.IPC_Get_Directory_Items, (event, data) => { + helpers + .grabDirectoryItems(data.Path, data.Version, data.Provider, data.Remote, data.S3) + .then(data => { + standardIPCReply(event, Constants.IPC_Get_Directory_Items_Reply, { + Items: data.items, + }); + }) + .catch(e => { + standardIPCReply(event, Constants.IPC_Get_Directory_Items_Reply, {}, e); + }); + }); + + ipcMain.on(Constants.IPC_Get_Pinned_Files, (event, data) => { + helpers + .grabDirectoryItems(data.Path, data.Version, data.Provider, data.Remote, data.S3) + .then(data => { + standardIPCReply(event, Constants.IPC_Get_Directory_Items_Reply, { + Items: data.items, + }); + }) + .catch(e => { + standardIPCReply(event, Constants.IPC_Get_Directory_Items_Reply, {}, e); + }); + }); + + ipcMain.on(Constants.IPC_Get_Pinned_Files_Status, (event, data) => { + + }); + + ipcMain.on(Constants.IPC_Set_Pinned + '_sync', (event, data) => { + helpers + .setPinned(data.Path, data.Pinned, data.Version, data.Provider, data.Remote, data.S3) + .then(success => { + event.returnValue = success; + }) + .catch(e => { + event.returnValue = false; + }); + }); +}; + +module.exports = { + addListeners +};