Prettier support
This commit is contained in:
6
.prettierrc.json
Normal file
6
.prettierrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -1,14 +1,30 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"APPIMAGE",
|
||||
"APPPLATFORM",
|
||||
"Filebase",
|
||||
"HKCC",
|
||||
"HKCR",
|
||||
"HKCU",
|
||||
"HKEY",
|
||||
"HKLM",
|
||||
"LOCALAPPDATA",
|
||||
"Redistributable",
|
||||
"Skylinks",
|
||||
"Skynet",
|
||||
"Unmount",
|
||||
"WINFSP",
|
||||
"blockstorage",
|
||||
"centos",
|
||||
"msiexec",
|
||||
"norestart",
|
||||
"randomstring",
|
||||
"reduxjs",
|
||||
"relver",
|
||||
"scprime",
|
||||
"siaprime",
|
||||
"skylink"
|
||||
"skylink",
|
||||
"undocked",
|
||||
"windir"
|
||||
]
|
||||
}
|
||||
238
CHANGELOG.md
238
CHANGELOG.md
@@ -1,153 +1,175 @@
|
||||
# Changelog
|
||||
|
||||
## 1.3.4
|
||||
* \#55: Enable 'Activate' release instead of 'Install' in notification pop-up
|
||||
|
||||
- \#55: Enable 'Activate' release instead of 'Install' in notification pop-up
|
||||
|
||||
## 1.3.3
|
||||
* \#49: Download progress is not visible if dependencies are missing
|
||||
* \#51: javascript error
|
||||
* \#52: Mount location is not set error on new install
|
||||
* \#53: Busy notification is still visible when 'Install' button is available
|
||||
* \#54: Unable to download UI update while dependencies are being checked
|
||||
* Disabled 'Install' button in new release notification
|
||||
|
||||
- \#49: Download progress is not visible if dependencies are missing
|
||||
- \#51: javascript error
|
||||
- \#52: Mount location is not set error on new install
|
||||
- \#53: Busy notification is still visible when 'Install' button is available
|
||||
- \#54: Unable to download UI update while dependencies are being checked
|
||||
- Disabled 'Install' button in new release notification
|
||||
|
||||
## 1.3.2
|
||||
* \#48: Support pinning files to cache
|
||||
* Fixed Skynet export display
|
||||
* Properly detect existing remote
|
||||
* Reduced number of Linux binaries to:
|
||||
* CentOS 7
|
||||
* Solus
|
||||
* S3 mount support [disabled]
|
||||
|
||||
- \#48: Support pinning files to cache
|
||||
- Fixed Skynet export display
|
||||
- Properly detect existing remote
|
||||
- Reduced number of Linux binaries to:
|
||||
- CentOS 7
|
||||
- Solus
|
||||
- S3 mount support [disabled]
|
||||
|
||||
## 1.3.1
|
||||
* \#45: Skynet mount support
|
||||
|
||||
- \#45: Skynet mount support
|
||||
|
||||
## 1.3.0
|
||||
* \#38: Enhance new repertory release available notification
|
||||
* \#46: Fix Mount Manager unmount and mount detection
|
||||
* Skynet support
|
||||
* Synchronize UI major/minor version with `repertory` major/minor version
|
||||
* Added `Password` component
|
||||
* Reduced number of Linux binaries to:
|
||||
* CentOS 7
|
||||
* Debian 9
|
||||
* Debian 10
|
||||
* Solus
|
||||
* Added `FocusTrap` to modals
|
||||
|
||||
- \#38: Enhance new repertory release available notification
|
||||
- \#46: Fix Mount Manager unmount and mount detection
|
||||
- Skynet support
|
||||
- Synchronize UI major/minor version with `repertory` major/minor version
|
||||
- Added `Password` component
|
||||
- Reduced number of Linux binaries to:
|
||||
- CentOS 7
|
||||
- Debian 9
|
||||
- Debian 10
|
||||
- Solus
|
||||
- Added `FocusTrap` to modals
|
||||
|
||||
## 1.1.4
|
||||
* \#39: Cleanup old releases and UI upgrades
|
||||
|
||||
- \#39: Cleanup old releases and UI upgrades
|
||||
|
||||
## 1.1.3
|
||||
* CentOS 8 support
|
||||
* Support remote send and receive timeouts
|
||||
* Support WinFSP mount manager
|
||||
* Fix `spawn()` failure on Windows when paths contain spaces
|
||||
|
||||
- CentOS 8 support
|
||||
- Support remote send and receive timeouts
|
||||
- Support WinFSP mount manager
|
||||
- Fix `spawn()` failure on Windows when paths contain spaces
|
||||
|
||||
## 1.1.2
|
||||
* Style changes
|
||||
|
||||
- Style changes
|
||||
|
||||
## 1.1.1
|
||||
* \#43: Support for remote UNIX mounts
|
||||
* Improved mount state detection
|
||||
|
||||
- \#43: Support for remote UNIX mounts
|
||||
- Improved mount state detection
|
||||
|
||||
## 1.1.0
|
||||
* \#40: Support for remote Windows mounts
|
||||
* \#42: Failing to unmount on OS X
|
||||
* Allow enabling dev tools (Ctrl-Shift-I or F12)
|
||||
* ScPrime re-brand
|
||||
* Ubuntu 19.10 support
|
||||
* Linux Mint 19.2 support
|
||||
* Fedora 31 support
|
||||
|
||||
- \#40: Support for remote Windows mounts
|
||||
- \#42: Failing to unmount on OS X
|
||||
- Allow enabling dev tools (Ctrl-Shift-I or F12)
|
||||
- ScPrime re-brand
|
||||
- Ubuntu 19.10 support
|
||||
- Linux Mint 19.2 support
|
||||
- Fedora 31 support
|
||||
|
||||
## 1.0.11 (Linux only)
|
||||
* Fix Ubuntu 19.10 detection
|
||||
|
||||
- Fix Ubuntu 19.10 detection
|
||||
|
||||
## 1.0.10
|
||||
* Fix VC runtime detection (detect additional GUID's)
|
||||
|
||||
- Fix VC runtime detection (detect additional GUID's)
|
||||
|
||||
## 1.0.9 (Alpha Testing Release)
|
||||
* \#40: Support for remote Windows mounts
|
||||
* ScPrime re-brand
|
||||
* Fix VC runtime detection (detect additional GUID's)
|
||||
|
||||
- \#40: Support for remote Windows mounts
|
||||
- ScPrime re-brand
|
||||
- Fix VC runtime detection (detect additional GUID's)
|
||||
|
||||
## 1.0.8
|
||||
* \#8: Add tooltips to settings
|
||||
* \#36: Add ability to select Linux distribution type if OS is unsupported
|
||||
* \#37: Version check fails with incorrect message when VC runtime is missing
|
||||
* Added additional WinFsp uninstall strings
|
||||
|
||||
- \#8: Add tooltips to settings
|
||||
- \#36: Add ability to select Linux distribution type if OS is unsupported
|
||||
- \#37: Version check fails with incorrect message when VC runtime is missing
|
||||
- Added additional WinFsp uninstall strings
|
||||
|
||||
## 1.0.7
|
||||
* \#31: New installation displays 'Mount location is not set' on Windows
|
||||
* \#33: Add 'Microsoft Visual C++ Redistributable' as dependency installation on Windows
|
||||
* \#32: Don't display network error message when check for UI updates fails
|
||||
* \#30: Add uninstall feature with reboot to handle WinFSP upgrades/downgrades
|
||||
* \#34: Allow cancelling/closing dependency installation if version count > 1
|
||||
* Handle incorrect download sizes for dependencies and releases
|
||||
|
||||
- \#31: New installation displays 'Mount location is not set' on Windows
|
||||
- \#33: Add 'Microsoft Visual C++ Redistributable' as dependency installation on Windows
|
||||
- \#32: Don't display network error message when check for UI updates fails
|
||||
- \#30: Add uninstall feature with reboot to handle WinFSP upgrades/downgrades
|
||||
- \#34: Allow cancelling/closing dependency installation if version count > 1
|
||||
- Handle incorrect download sizes for dependencies and releases
|
||||
|
||||
## 1.0.6
|
||||
* Additional Linux distribution support:
|
||||
* Antergos
|
||||
* Manjaro
|
||||
* Download latest `detect_linux.sh` if bundled script returns `unknown`
|
||||
* Display error message if OS is detected as `unknown`
|
||||
|
||||
- Additional Linux distribution support:
|
||||
- Antergos
|
||||
- Manjaro
|
||||
- Download latest `detect_linux.sh` if bundled script returns `unknown`
|
||||
- Display error message if OS is detected as `unknown`
|
||||
|
||||
## 1.0.5
|
||||
* \#29: Mounts aren't being detected properly when switching releases
|
||||
* Display window when dependencies are missing
|
||||
* Display window when UI upgrade is available
|
||||
* Display window and unmount all drives if release is no longer available
|
||||
* Will primarily affect pre-release versions (Alpha, Beta, and RC)
|
||||
|
||||
- \#29: Mounts aren't being detected properly when switching releases
|
||||
- Display window when dependencies are missing
|
||||
- Display window when UI upgrade is available
|
||||
- Display window and unmount all drives if release is no longer available
|
||||
- Will primarily affect pre-release versions (Alpha, Beta, and RC)
|
||||
|
||||
## 1.0.4
|
||||
* \#27: Implement Bitbucket backup download location
|
||||
* \#28: Fix Linux upgrade
|
||||
* Additional Linux distribution support:
|
||||
* Debian 10
|
||||
* OpenSUSE Leap 15.0
|
||||
* OpenSUSE Leap 15.1
|
||||
* OpenSUSE Tumbleweed
|
||||
|
||||
- \#27: Implement Bitbucket backup download location
|
||||
- \#28: Fix Linux upgrade
|
||||
- Additional Linux distribution support:
|
||||
- Debian 10
|
||||
- OpenSUSE Leap 15.0
|
||||
- OpenSUSE Leap 15.1
|
||||
- OpenSUSE Tumbleweed
|
||||
|
||||
## 1.0.3
|
||||
* Linux distribution support
|
||||
* Arch Linux
|
||||
* Bodhi 5.0.0
|
||||
* CentOS 7
|
||||
* Debian 9
|
||||
* Elementary OS 5.0
|
||||
* Fedora 28
|
||||
* Fedora 29
|
||||
* Fedora 30
|
||||
* Linux Mint 19
|
||||
* Linux Mint 19.1
|
||||
* Solus
|
||||
* Ubuntu 18.04
|
||||
* Ubuntu 18.10
|
||||
* Ubuntu 19.04
|
||||
* Removed `react-css-modules` dependency
|
||||
* Removed Hyperspace (no active development/insufficient host network)
|
||||
* Restore main window on error message
|
||||
|
||||
- Linux distribution support
|
||||
- Arch Linux
|
||||
- Bodhi 5.0.0
|
||||
- CentOS 7
|
||||
- Debian 9
|
||||
- Elementary OS 5.0
|
||||
- Fedora 28
|
||||
- Fedora 29
|
||||
- Fedora 30
|
||||
- Linux Mint 19
|
||||
- Linux Mint 19.1
|
||||
- Solus
|
||||
- Ubuntu 18.04
|
||||
- Ubuntu 18.10
|
||||
- Ubuntu 19.04
|
||||
- Removed `react-css-modules` dependency
|
||||
- Removed Hyperspace (no active development/insufficient host network)
|
||||
- Restore main window on error message
|
||||
|
||||
## 1.0.2
|
||||
* Option to launch application hidden (notification icon only)
|
||||
* Close window to notification area
|
||||
* Unmount on application exit
|
||||
* Ability to cancel mount retry on unexpected failure
|
||||
* OS X support
|
||||
* SiaPrime support
|
||||
* Partial Linux support
|
||||
* Electron to v4
|
||||
* Prevent mount if dependencies are missing
|
||||
|
||||
- Option to launch application hidden (notification icon only)
|
||||
- Close window to notification area
|
||||
- Unmount on application exit
|
||||
- Ability to cancel mount retry on unexpected failure
|
||||
- OS X support
|
||||
- SiaPrime support
|
||||
- Partial Linux support
|
||||
- Electron to v4
|
||||
- Prevent mount if dependencies are missing
|
||||
|
||||
## 1.0.1
|
||||
* Added configuration settings for Repertory 1.0.0-alpha.2 and above
|
||||
* Fixed memory leak on component unmount
|
||||
* Added error display
|
||||
* Lighter tray icon on Windows
|
||||
* Tray icon indicates mount status on Windows
|
||||
* Various fixes/layout changes
|
||||
|
||||
- Added configuration settings for Repertory 1.0.0-alpha.2 and above
|
||||
- Fixed memory leak on component unmount
|
||||
- Added error display
|
||||
- Lighter tray icon on Windows
|
||||
- Tray icon indicates mount status on Windows
|
||||
- Various fixes/layout changes
|
||||
|
||||
## 1.0.0
|
||||
* Initial release
|
||||
* Windows support
|
||||
|
||||
- Initial release
|
||||
- Windows support
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Repertory UI
|
||||
* Lars Floe <lars@krankajen.se>
|
||||
* Oleg Nypadymka <onypadymka@gmail.com>
|
||||
* Scott E. Graves <scott.e.graves@protonmail.com>
|
||||
|
||||
- Lars Floe <lars@krankajen.se>
|
||||
- Oleg Nypadymka <onypadymka@gmail.com>
|
||||
- Scott E. Graves <scott.e.graves@protonmail.com>
|
||||
|
||||
@@ -5,7 +5,7 @@ const {
|
||||
ipcMain,
|
||||
Menu,
|
||||
nativeImage,
|
||||
Tray
|
||||
Tray,
|
||||
} = require('electron');
|
||||
const AutoLaunch = require('auto-launch');
|
||||
const Constants = require('../src/constants');
|
||||
@@ -44,12 +44,12 @@ const UpgradeIPC = require('../src/renderer/ipc/UpgradeIPC');
|
||||
const platform = os.platform();
|
||||
|
||||
const dimensions = {
|
||||
height: (platform === 'win32') ? 326 : (platform === 'darwin') ? 322 : 300,
|
||||
width: (platform === 'win32') ? 468 : 628,
|
||||
height: platform === 'win32' ? 326 : platform === 'darwin' ? 322 : 300,
|
||||
width: platform === 'win32' ? 468 : 628,
|
||||
};
|
||||
|
||||
let isShutdown = false;
|
||||
let isQuiting = false;
|
||||
let isQuitting = false;
|
||||
let isInstalling = false;
|
||||
let launchHidden = false;
|
||||
let cleanupReleases = false;
|
||||
@@ -88,7 +88,7 @@ const createWindow = () => {
|
||||
if (platform === 'linux') {
|
||||
extra = {
|
||||
icon: path.join(__dirname, '../build/', 'logo.png'),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Create the browser window.
|
||||
@@ -102,27 +102,29 @@ const createWindow = () => {
|
||||
...extra,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
webSecurity: !process.env.ELECTRON_START_URL
|
||||
}
|
||||
webSecurity: !process.env.ELECTRON_START_URL,
|
||||
},
|
||||
});
|
||||
if (platform === 'linux') {
|
||||
mainWindow.setMenuBarVisibility(false);
|
||||
} else {
|
||||
mainWindow.removeMenu();
|
||||
}
|
||||
if ((platform === 'darwin') && launchHidden) {
|
||||
if (platform === 'darwin' && launchHidden) {
|
||||
app.dock.hide();
|
||||
}
|
||||
|
||||
// and load the index.html of the app.
|
||||
const startUrl = process.env.ELECTRON_START_URL || url.format({
|
||||
pathname: path.join(__dirname, '../build/index.html'),
|
||||
protocol: 'file:',
|
||||
slashes: true
|
||||
});
|
||||
const startUrl =
|
||||
process.env.ELECTRON_START_URL ||
|
||||
url.format({
|
||||
pathname: path.join(__dirname, '../build/index.html'),
|
||||
protocol: 'file:',
|
||||
slashes: true,
|
||||
});
|
||||
|
||||
mainWindow.on('close', function (event) {
|
||||
if (!isQuiting) {
|
||||
if (!isQuitting) {
|
||||
event.preventDefault();
|
||||
if (mainWindow.isVisible()) {
|
||||
setWindowVisibility(false);
|
||||
@@ -140,9 +142,14 @@ const createWindow = () => {
|
||||
MountsIPC.unmountAllDrives();
|
||||
});
|
||||
|
||||
const appPath = (platform === 'win32') ? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')) :
|
||||
(platform === 'darwin') ? path.resolve(path.join(path.dirname(app.getAppPath()), '../MacOS/repertory-ui')) :
|
||||
process.env.APPIMAGE;
|
||||
const appPath =
|
||||
platform === 'win32'
|
||||
? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe'))
|
||||
: platform === 'darwin'
|
||||
? path.resolve(
|
||||
path.join(path.dirname(app.getAppPath()), '../MacOS/repertory-ui')
|
||||
)
|
||||
: process.env.APPIMAGE;
|
||||
|
||||
const autoLauncher = new AutoLaunch({
|
||||
name: 'Repertory UI',
|
||||
@@ -151,51 +158,59 @@ const createWindow = () => {
|
||||
|
||||
trayContextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'Visible', type: 'checkbox', click(item) {
|
||||
label: 'Visible',
|
||||
type: 'checkbox',
|
||||
click(item) {
|
||||
setWindowVisibility(item.checked);
|
||||
},
|
||||
checked: !launchHidden,
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Auto-start', type: 'checkbox', click(item) {
|
||||
label: 'Auto-start',
|
||||
type: 'checkbox',
|
||||
click(item) {
|
||||
if (item.checked) {
|
||||
autoLauncher.enable();
|
||||
} else {
|
||||
autoLauncher.disable();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Launch Hidden', type: 'checkbox', click(item) {
|
||||
label: 'Launch Hidden',
|
||||
type: 'checkbox',
|
||||
click(item) {
|
||||
launchHidden = !!item.checked;
|
||||
saveUiSettings();
|
||||
},
|
||||
checked: launchHidden,
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Delete Old Releases', type: 'checkbox', click(item) {
|
||||
label: 'Delete Old Releases',
|
||||
type: 'checkbox',
|
||||
click(item) {
|
||||
cleanupReleases = !!item.checked;
|
||||
saveUiSettings();
|
||||
},
|
||||
checked: cleanupReleases,
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Exit and Unmount', click() {
|
||||
label: 'Exit and Unmount',
|
||||
click() {
|
||||
closeApplication();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const image = nativeImage.createFromPath(path.join(__dirname, (platform === 'darwin') ? '../build/logo_mac.png' : '../build/logo.png'));
|
||||
const image = nativeImage.createFromPath(
|
||||
path.join(
|
||||
__dirname,
|
||||
platform === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'
|
||||
)
|
||||
);
|
||||
mainWindowTray = new Tray(image);
|
||||
|
||||
autoLauncher
|
||||
@@ -203,7 +218,7 @@ const createWindow = () => {
|
||||
.then((enabled) => {
|
||||
trayContextMenu.items[2].checked = enabled;
|
||||
mainWindowTray.setToolTip('Repertory UI');
|
||||
mainWindowTray.setContextMenu(trayContextMenu)
|
||||
mainWindowTray.setContextMenu(trayContextMenu);
|
||||
})
|
||||
.catch(() => {
|
||||
closeApplication();
|
||||
@@ -217,7 +232,10 @@ const getMainWindow = () => {
|
||||
};
|
||||
|
||||
const loadUiSettings = () => {
|
||||
const settingFile = path.join(helpers.resolvePath(Constants.DATA_LOCATIONS[platform]), 'ui.json');
|
||||
const settingFile = path.join(
|
||||
helpers.resolvePath(Constants.DATA_LOCATIONS[platform]),
|
||||
'ui.json'
|
||||
);
|
||||
try {
|
||||
if (fs.statSync(settingFile).isFile()) {
|
||||
const settings = JSON.parse(fs.readFileSync(settingFile, 'utf8'));
|
||||
@@ -225,37 +243,51 @@ const loadUiSettings = () => {
|
||||
cleanupReleases = !!settings.cleanup_releases;
|
||||
PlatformIPC.setPlatformOverride(settings.platform_override);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
const saveUiSettings = () => {
|
||||
const settingFile = path.join(helpers.getDataDirectory(), 'ui.json');
|
||||
try {
|
||||
fs.writeFileSync(settingFile, JSON.stringify({
|
||||
cleanup_releases: cleanupReleases,
|
||||
launch_hidden: launchHidden,
|
||||
platform_override: PlatformIPC.getPlatformOverride(),
|
||||
}), 'utf-8');
|
||||
} catch (e) {
|
||||
}
|
||||
fs.writeFileSync(
|
||||
settingFile,
|
||||
JSON.stringify({
|
||||
cleanup_releases: cleanupReleases,
|
||||
launch_hidden: launchHidden,
|
||||
platform_override: PlatformIPC.getPlatformOverride(),
|
||||
}),
|
||||
'utf-8'
|
||||
);
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
const setIsInstalling = installing => {
|
||||
const setIsInstalling = (installing) => {
|
||||
isInstalling = installing;
|
||||
};
|
||||
|
||||
const setTrayImage = driveInUse => {
|
||||
const setTrayImage = (driveInUse) => {
|
||||
let image;
|
||||
if (driveInUse) {
|
||||
image = nativeImage.createFromPath(path.join(__dirname, platform === 'darwin' ? '../build/logo_both_mac.png' : '../build/logo_both.png'));
|
||||
image = nativeImage.createFromPath(
|
||||
path.join(
|
||||
__dirname,
|
||||
platform === 'darwin'
|
||||
? '../build/logo_both_mac.png'
|
||||
: '../build/logo_both.png'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
image = nativeImage.createFromPath(path.join(__dirname, platform === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'));
|
||||
image = nativeImage.createFromPath(
|
||||
path.join(
|
||||
__dirname,
|
||||
platform === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'
|
||||
)
|
||||
);
|
||||
}
|
||||
mainWindowTray.setImage(image);
|
||||
};
|
||||
|
||||
const setWindowVisibility = show => {
|
||||
const setWindowVisibility = (show) => {
|
||||
if (show) {
|
||||
mainWindow.show();
|
||||
if (platform === 'darwin') {
|
||||
@@ -277,7 +309,7 @@ const setWindowVisibility = show => {
|
||||
|
||||
if (trayContextMenu && mainWindowTray) {
|
||||
trayContextMenu.items[0].checked = show;
|
||||
mainWindowTray.setContextMenu(trayContextMenu)
|
||||
mainWindowTray.setContextMenu(trayContextMenu);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -288,13 +320,13 @@ const standardIPCReply = (event, channel, data, error) => {
|
||||
...data,
|
||||
Error: error instanceof Error ? error.toString() : error,
|
||||
Success: !error,
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
app.on('before-quit', function () {
|
||||
isQuiting = true;
|
||||
isQuitting = true;
|
||||
});
|
||||
|
||||
let instanceLock = app.requestSingleInstanceLock();
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta charset="utf-8"/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css?family=Nunito:400,700" rel="stylesheet">
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Nunito:400,700"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
@@ -24,9 +30,7 @@
|
||||
<title>Repertory UI</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<noscript> You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
|
||||
304
src/App.jsx
304
src/App.jsx
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import './App.css';
|
||||
import Box from './components/UI/Box/Box';
|
||||
import Configuration from './containers/Configuration/Configuration';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import DependencyList from './components/DependencyList/DependencyList';
|
||||
import DownloadProgress from './components/DownloadProgress/DownloadProgress';
|
||||
import ErrorDetails from './components/ErrorDetails/ErrorDetails';
|
||||
@@ -11,17 +11,17 @@ import InfoDetails from './components/InfoDetails/InfoDetails';
|
||||
import IPCContainer from './containers/IPCContainer/IPCContainer';
|
||||
import Loading from './components/UI/Loading/Loading';
|
||||
import MountItems from './containers/MountItems/MountItems';
|
||||
import NewReleases from './components/NewReleases/NewReleases';
|
||||
import {notifyError} from './redux/actions/error_actions';
|
||||
import NewReleases from './components/NewReleases/NewReleases.jsx';
|
||||
import { notifyError } from './redux/actions/error_actions';
|
||||
import Reboot from './components/Reboot/Reboot';
|
||||
import {
|
||||
setDismissNewReleasesAvailable,
|
||||
setNewReleasesAvailable
|
||||
setNewReleasesAvailable,
|
||||
} from './redux/actions/release_version_actions';
|
||||
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
||||
import {
|
||||
displaySelectAppPlatform,
|
||||
saveState
|
||||
saveState,
|
||||
} from './redux/actions/common_actions';
|
||||
import SelectAppPlatform from './containers/SelectAppPlatform/SelectAppPlatform';
|
||||
import Text from './components/UI/Text/Text';
|
||||
@@ -29,10 +29,10 @@ import UpgradeIcon from './components/UpgradeIcon/UpgradeIcon';
|
||||
import UpgradeUI from './components/UpgradeUI/UpgradeUI';
|
||||
import {
|
||||
loadReleases,
|
||||
setDismissUIUpgrade
|
||||
setDismissUIUpgrade,
|
||||
} from './redux/actions/release_version_actions';
|
||||
import YesNo from './components/YesNo/YesNo';
|
||||
import {createModalConditionally} from './utils';
|
||||
import { createModalConditionally } from './utils.jsx';
|
||||
import SkynetImport from './containers/SkynetImport/SkynetImport';
|
||||
import ApplicationBusy from './components/ApplicationBusy/ApplicationBusy';
|
||||
import SkynetExport from './containers/SkynetExport/SkynetExport';
|
||||
@@ -59,13 +59,17 @@ class App extends IPCContainer {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if ((prevProps.Release !== this.props.Release) ||
|
||||
(prevProps.ReleaseVersion !== this.props.ReleaseVersion) ||
|
||||
(prevProps.VersionLookup !== this.props.VersionLookup)) {
|
||||
if (
|
||||
prevProps.Release !== this.props.Release ||
|
||||
prevProps.ReleaseVersion !== this.props.ReleaseVersion ||
|
||||
prevProps.VersionLookup !== this.props.VersionLookup
|
||||
) {
|
||||
this.props.saveState();
|
||||
} else if (Object.keys(this.props.ProviderState).filter(k => {
|
||||
return this.props.ProviderState[k] !== prevProps.ProviderState[k];
|
||||
}).length > 0) {
|
||||
} else if (
|
||||
Object.keys(this.props.ProviderState).filter((k) => {
|
||||
return this.props.ProviderState[k] !== prevProps.ProviderState[k];
|
||||
}).length > 0
|
||||
) {
|
||||
this.props.saveState();
|
||||
}
|
||||
}
|
||||
@@ -76,14 +80,16 @@ class App extends IPCContainer {
|
||||
}
|
||||
|
||||
getSelectedVersion = () => {
|
||||
return (this.props.ReleaseVersion === -1) ?
|
||||
'unavailable' :
|
||||
this.props.VersionLookup[Constants.RELEASE_TYPES[this.props.Release]][this.props.ReleaseVersion];
|
||||
return this.props.ReleaseVersion === -1
|
||||
? 'unavailable'
|
||||
: this.props.VersionLookup[Constants.RELEASE_TYPES[this.props.Release]][
|
||||
this.props.ReleaseVersion
|
||||
];
|
||||
};
|
||||
|
||||
handleUpgradeIconClicked = () => {
|
||||
if (this.props.UpgradeAvailable) {
|
||||
this.props.setDismissUIUpgrade(false)
|
||||
this.props.setDismissUIUpgrade(false);
|
||||
} else if (this.props.NewReleasesAvailable2.length > 0) {
|
||||
this.props.setNewReleasesAvailable(this.props.NewReleasesAvailable2);
|
||||
this.props.setDismissNewReleasesAvailable(false);
|
||||
@@ -93,44 +99,54 @@ class App extends IPCContainer {
|
||||
render() {
|
||||
const selectedVersion = this.getSelectedVersion();
|
||||
|
||||
const downloadEnabled = this.props.AllowDownload &&
|
||||
const downloadEnabled =
|
||||
this.props.AllowDownload &&
|
||||
!this.props.MountsBusy &&
|
||||
!this.props.DownloadActive &&
|
||||
(selectedVersion !== 'unavailable') &&
|
||||
(selectedVersion !== this.props.InstalledVersion);
|
||||
const missingDependencies = (this.props.MissingDependencies.length > 0) &&
|
||||
this.props.AllowMount;
|
||||
selectedVersion !== 'unavailable' &&
|
||||
selectedVersion !== this.props.InstalledVersion;
|
||||
const missingDependencies =
|
||||
this.props.MissingDependencies.length > 0 && this.props.AllowMount;
|
||||
|
||||
const allowMount = this.props.AllowMount &&
|
||||
const allowMount =
|
||||
this.props.AllowMount &&
|
||||
this.props.InstalledVersion !== 'none' &&
|
||||
!missingDependencies &&
|
||||
!this.props.InstallActive;
|
||||
|
||||
const remoteSupported = this.props.LocationsLookup[selectedVersion] &&
|
||||
const remoteSupported =
|
||||
this.props.LocationsLookup[selectedVersion] &&
|
||||
this.props.LocationsLookup[selectedVersion].supports_remote;
|
||||
|
||||
const s3Supported = this.props.LocationsLookup[selectedVersion] &&
|
||||
const s3Supported =
|
||||
this.props.LocationsLookup[selectedVersion] &&
|
||||
this.props.LocationsLookup[selectedVersion].s3_support;
|
||||
|
||||
const skynetSupported = this.props.LocationsLookup[selectedVersion] &&
|
||||
const skynetSupported =
|
||||
this.props.LocationsLookup[selectedVersion] &&
|
||||
this.props.LocationsLookup[selectedVersion].skynet_support;
|
||||
|
||||
const scPrimeSupported = this.props.LocationsLookup[selectedVersion] &&
|
||||
const scPrimeSupported =
|
||||
this.props.LocationsLookup[selectedVersion] &&
|
||||
this.props.LocationsLookup[selectedVersion].siaprime_support;
|
||||
|
||||
const siaSupported = this.props.LocationsLookup[selectedVersion] &&
|
||||
const siaSupported =
|
||||
this.props.LocationsLookup[selectedVersion] &&
|
||||
this.props.LocationsLookup[selectedVersion].sia_support;
|
||||
|
||||
const showConfig = !missingDependencies &&
|
||||
const showConfig =
|
||||
!missingDependencies &&
|
||||
!this.props.DisplayPinnedManager &&
|
||||
this.props.DisplayConfiguration &&
|
||||
!this.props.RebootRequired;
|
||||
|
||||
const showPinnedManager = !missingDependencies &&
|
||||
const showPinnedManager =
|
||||
!missingDependencies &&
|
||||
!this.props.RebootRequired &&
|
||||
this.props.DisplayPinnedManager;
|
||||
|
||||
const showUpgrade = this.props.UpgradeAvailable &&
|
||||
const showUpgrade =
|
||||
this.props.UpgradeAvailable &&
|
||||
!this.props.DisplayError &&
|
||||
!showConfig &&
|
||||
!this.props.DownloadActive &&
|
||||
@@ -138,14 +154,16 @@ class App extends IPCContainer {
|
||||
!this.props.InstallActive &&
|
||||
!this.props.RebootRequired;
|
||||
|
||||
const showDependencies = !showUpgrade &&
|
||||
const showDependencies =
|
||||
!showUpgrade &&
|
||||
missingDependencies &&
|
||||
!this.props.DownloadActive &&
|
||||
!this.props.RebootRequired &&
|
||||
!this.props.DismissDependencies &&
|
||||
this.props.AllowMount;
|
||||
|
||||
const showNewReleases = !showConfig &&
|
||||
const showNewReleases =
|
||||
!showConfig &&
|
||||
!this.props.DisplayConfirmYesNo &&
|
||||
!showDependencies &&
|
||||
!this.props.DownloadActive &&
|
||||
@@ -156,9 +174,10 @@ class App extends IPCContainer {
|
||||
!this.props.DisplaySelectAppPlatform &&
|
||||
!showUpgrade &&
|
||||
!this.props.DismissNewReleasesAvailable &&
|
||||
(this.props.NewReleasesAvailable.length > 0);
|
||||
this.props.NewReleasesAvailable.length > 0;
|
||||
|
||||
const showSkynetImport = !showConfig &&
|
||||
const showSkynetImport =
|
||||
!showConfig &&
|
||||
!showDependencies &&
|
||||
!this.props.DownloadActive &&
|
||||
!showNewReleases &&
|
||||
@@ -167,7 +186,8 @@ class App extends IPCContainer {
|
||||
!showUpgrade &&
|
||||
this.props.DisplayImport;
|
||||
|
||||
const showSkynetExport = !showConfig &&
|
||||
const showSkynetExport =
|
||||
!showConfig &&
|
||||
!showDependencies &&
|
||||
!this.props.DownloadActive &&
|
||||
!showNewReleases &&
|
||||
@@ -176,66 +196,123 @@ class App extends IPCContainer {
|
||||
!showUpgrade &&
|
||||
this.props.DisplayExport;
|
||||
|
||||
const configDisplay = createModalConditionally(showConfig, <Configuration
|
||||
version={selectedVersion}
|
||||
s3Supported={s3Supported}
|
||||
remoteSupported={remoteSupported}/>);
|
||||
const pinnedManagerDisplay = createModalConditionally(showPinnedManager, <PinnedManager
|
||||
version={selectedVersion}/>)
|
||||
const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, <YesNo/>);
|
||||
const dependencyDisplay = createModalConditionally(showDependencies,
|
||||
<DependencyList/>, false, this.props.InstallActive);
|
||||
const downloadDisplay = createModalConditionally(this.props.DownloadActive,
|
||||
<DownloadProgress/>, false, true);
|
||||
const errorDisplay = createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
|
||||
const infoDisplay = createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true);
|
||||
const newReleasesDisplay = createModalConditionally(showNewReleases, <NewReleases/>);
|
||||
const rebootDisplay = createModalConditionally(this.props.RebootRequired, <Reboot/>);
|
||||
const selectAppPlatformDisplay = createModalConditionally(this.props.DisplaySelectAppPlatform,
|
||||
<SelectAppPlatform/>);
|
||||
const upgradeDisplay = createModalConditionally(showUpgrade, <UpgradeUI/>);
|
||||
const importDisplay = createModalConditionally(showSkynetImport, <SkynetImport
|
||||
version={selectedVersion}/>);
|
||||
const exportDisplay = createModalConditionally(showSkynetExport, <SkynetExport
|
||||
version={selectedVersion}/>)
|
||||
const appBusyDisplay = createModalConditionally(this.props.AppBusy,
|
||||
<ApplicationBusy/>, false, true, this.props.AppBusyTransparent);
|
||||
const configDisplay = createModalConditionally(
|
||||
showConfig,
|
||||
<Configuration
|
||||
version={selectedVersion}
|
||||
s3Supported={s3Supported}
|
||||
remoteSupported={remoteSupported}
|
||||
/>
|
||||
);
|
||||
const pinnedManagerDisplay = createModalConditionally(
|
||||
showPinnedManager,
|
||||
<PinnedManager version={selectedVersion} />
|
||||
);
|
||||
const confirmDisplay = createModalConditionally(
|
||||
this.props.DisplayConfirmYesNo,
|
||||
<YesNo />
|
||||
);
|
||||
const dependencyDisplay = createModalConditionally(
|
||||
showDependencies,
|
||||
<DependencyList />,
|
||||
false,
|
||||
this.props.InstallActive
|
||||
);
|
||||
const downloadDisplay = createModalConditionally(
|
||||
this.props.DownloadActive,
|
||||
<DownloadProgress />,
|
||||
false,
|
||||
true
|
||||
);
|
||||
const errorDisplay = createModalConditionally(
|
||||
this.props.DisplayError,
|
||||
<ErrorDetails />,
|
||||
true
|
||||
);
|
||||
const infoDisplay = createModalConditionally(
|
||||
this.props.DisplayInfo,
|
||||
<InfoDetails />,
|
||||
true
|
||||
);
|
||||
const newReleasesDisplay = createModalConditionally(
|
||||
showNewReleases,
|
||||
<NewReleases />
|
||||
);
|
||||
const rebootDisplay = createModalConditionally(
|
||||
this.props.RebootRequired,
|
||||
<Reboot />
|
||||
);
|
||||
const selectAppPlatformDisplay = createModalConditionally(
|
||||
this.props.DisplaySelectAppPlatform,
|
||||
<SelectAppPlatform />
|
||||
);
|
||||
const upgradeDisplay = createModalConditionally(showUpgrade, <UpgradeUI />);
|
||||
const importDisplay = createModalConditionally(
|
||||
showSkynetImport,
|
||||
<SkynetImport version={selectedVersion} />
|
||||
);
|
||||
const exportDisplay = createModalConditionally(
|
||||
showSkynetExport,
|
||||
<SkynetExport version={selectedVersion} />
|
||||
);
|
||||
const appBusyDisplay = createModalConditionally(
|
||||
this.props.AppBusy,
|
||||
<ApplicationBusy />,
|
||||
false,
|
||||
true,
|
||||
this.props.AppBusyTransparent
|
||||
);
|
||||
|
||||
let mainContent = [];
|
||||
if (this.props.DisplaySelectAppPlatform || !this.props.AppReady) {
|
||||
mainContent = (
|
||||
<Box dxStyle={{height: '100%'}}>
|
||||
<Loading/>
|
||||
</Box>);
|
||||
<Box dxStyle={{ height: '100%' }}>
|
||||
<Loading />
|
||||
</Box>
|
||||
);
|
||||
} else {
|
||||
let key = 0;
|
||||
mainContent.push((
|
||||
<Box key={'md_' + key++}
|
||||
dxStyle={{padding: 'var(--default_spacing)', height: 'auto'}}>
|
||||
<ReleaseVersionDisplay downloadDisabled={!downloadEnabled}
|
||||
version={selectedVersion}/>
|
||||
mainContent.push(
|
||||
<Box
|
||||
key={'md_' + key++}
|
||||
dxStyle={{ padding: 'var(--default_spacing)', height: 'auto' }}
|
||||
>
|
||||
<ReleaseVersionDisplay
|
||||
downloadDisabled={!downloadEnabled}
|
||||
version={selectedVersion}
|
||||
/>
|
||||
</Box>
|
||||
));
|
||||
mainContent.push(<div key={'md_' + key++}
|
||||
style={{paddingTop: 'var(--default_spacing)'}}/>);
|
||||
);
|
||||
mainContent.push(
|
||||
<div
|
||||
key={'md_' + key++}
|
||||
style={{ paddingTop: 'var(--default_spacing)' }}
|
||||
/>
|
||||
);
|
||||
if (allowMount) {
|
||||
mainContent.push((
|
||||
<Box dxStyle={{padding: 'var(--default_spacing)', height: 'auto'}}
|
||||
key={'md_' + key++}>
|
||||
<MountItems s3Supported={s3Supported}
|
||||
remoteSupported={remoteSupported}
|
||||
scPrimeSupported={scPrimeSupported}
|
||||
siaSupported={siaSupported}
|
||||
skynetSupported={skynetSupported}/>
|
||||
mainContent.push(
|
||||
<Box
|
||||
dxStyle={{ padding: 'var(--default_spacing)', height: 'auto' }}
|
||||
key={'md_' + key++}
|
||||
>
|
||||
<MountItems
|
||||
s3Supported={s3Supported}
|
||||
remoteSupported={remoteSupported}
|
||||
scPrimeSupported={scPrimeSupported}
|
||||
siaSupported={siaSupported}
|
||||
skynetSupported={skynetSupported}
|
||||
/>
|
||||
</Box>
|
||||
));
|
||||
} else if (!downloadEnabled && (selectedVersion !== 'unavailable')) {
|
||||
mainContent.push((
|
||||
<Box dxStyle={{padding: 'var(--default_spacing)', height: '170px'}}
|
||||
key={'md_' + key++}>
|
||||
<Loading/>
|
||||
);
|
||||
} else if (!downloadEnabled && selectedVersion !== 'unavailable') {
|
||||
mainContent.push(
|
||||
<Box
|
||||
dxStyle={{ padding: 'var(--default_spacing)', height: '170px' }}
|
||||
key={'md_' + key++}
|
||||
>
|
||||
<Loading />
|
||||
</Box>
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,27 +322,36 @@ class App extends IPCContainer {
|
||||
<div className={'AppHeader'}>
|
||||
<Box>
|
||||
<Grid>
|
||||
<Text col={0}
|
||||
colSpan={'remain'}
|
||||
row={0}
|
||||
rowSpan={'remain'}
|
||||
text={'Repertory UI v' + this.props.Version}
|
||||
textAlign={'center'}
|
||||
type={'Heading1'}/>
|
||||
<Text
|
||||
col={0}
|
||||
colSpan={'remain'}
|
||||
row={0}
|
||||
rowSpan={'remain'}
|
||||
text={'Repertory UI v' + this.props.Version}
|
||||
textAlign={'center'}
|
||||
type={'Heading1'}
|
||||
/>
|
||||
<UpgradeIcon
|
||||
available={!missingDependencies && (this.props.UpgradeAvailable || (this.props.NewReleasesAvailable2.length > 0))}
|
||||
newReleases={!missingDependencies && (!this.props.UpgradeAvailable && (this.props.NewReleasesAvailable2.length > 0))}
|
||||
available={
|
||||
!missingDependencies &&
|
||||
(this.props.UpgradeAvailable ||
|
||||
this.props.NewReleasesAvailable2.length > 0)
|
||||
}
|
||||
newReleases={
|
||||
!missingDependencies &&
|
||||
!this.props.UpgradeAvailable &&
|
||||
this.props.NewReleasesAvailable2.length > 0
|
||||
}
|
||||
clicked={this.handleUpgradeIconClicked}
|
||||
col={dimensions => dimensions.columns - 6}
|
||||
col={(dimensions) => dimensions.columns - 6}
|
||||
colSpan={5}
|
||||
row={1}
|
||||
rowSpan={remain => remain - 1}/>
|
||||
rowSpan={(remain) => remain - 1}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
</div>
|
||||
<div className={'AppContent'}>
|
||||
{mainContent}
|
||||
</div>
|
||||
<div className={'AppContent'}>{mainContent}</div>
|
||||
</div>
|
||||
{importDisplay}
|
||||
{exportDisplay}
|
||||
@@ -286,7 +372,7 @@ class App extends IPCContainer {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
AllowDownload: state.download.AllowDownload,
|
||||
AllowMount: state.common.AllowMount,
|
||||
@@ -324,15 +410,19 @@ const mapStateToProps = state => {
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
displaySelectAppPlatform: display => dispatch(displaySelectAppPlatform(display)),
|
||||
displaySelectAppPlatform: (display) =>
|
||||
dispatch(displaySelectAppPlatform(display)),
|
||||
loadReleases: () => dispatch(loadReleases()),
|
||||
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
|
||||
notifyError: (msg, critical, callback) =>
|
||||
dispatch(notifyError(msg, critical, callback)),
|
||||
saveState: () => dispatch(saveState()),
|
||||
setDismissNewReleasesAvailable: dismiss => dispatch(setDismissNewReleasesAvailable(dismiss)),
|
||||
setNewReleasesAvailable: items => dispatch(setNewReleasesAvailable(items)),
|
||||
setDismissUIUpgrade: dismiss => dispatch(setDismissUIUpgrade(dismiss)),
|
||||
setDismissNewReleasesAvailable: (dismiss) =>
|
||||
dispatch(setDismissNewReleasesAvailable(dismiss)),
|
||||
setNewReleasesAvailable: (items) =>
|
||||
dispatch(setNewReleasesAvailable(items)),
|
||||
setDismissUIUpgrade: (dismiss) => dispatch(setDismissUIUpgrade(dismiss)),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -3,18 +3,26 @@ import Box from '../UI/Box/Box';
|
||||
import Loader from 'react-loader-spinner';
|
||||
import Text from '../UI/Text/Text';
|
||||
|
||||
const ApplicationBusy = ({title}) => {
|
||||
const ApplicationBusy = ({ title }) => {
|
||||
return (
|
||||
<Box dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||
<Box dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<Text
|
||||
text={title || 'Please Wait...'}
|
||||
textAlign={'center'}
|
||||
type={'Heading1'}/>
|
||||
<div style={{paddingLeft: 'calc(50% - 16px)', paddingTop: 'var(--default_spacing)'}}>
|
||||
<Loader color={'var(--heading_text_color)'}
|
||||
height={32}
|
||||
width={32}
|
||||
type='TailSpin'/>
|
||||
type={'Heading1'}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: 'calc(50% - 16px)',
|
||||
paddingTop: 'var(--default_spacing)',
|
||||
}}
|
||||
>
|
||||
<Loader
|
||||
color={'var(--heading_text_color)'}
|
||||
height={32}
|
||||
width={32}
|
||||
type="TailSpin"
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import React from 'react';
|
||||
import './Dependency.css';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Constants from '../../../constants';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
AllowDownload: (state.download.DownloadType !== Constants.INSTALL_TYPES.Dependency) &&
|
||||
AllowDownload:
|
||||
state.download.DownloadType !== Constants.INSTALL_TYPES.Dependency &&
|
||||
!state.download.DownloadActive &&
|
||||
!state.install.InstallActive,
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(props => {
|
||||
export default connect(mapStateToProps)((props) => {
|
||||
return (
|
||||
<div className={'Dependency'}>
|
||||
<table width="100%">
|
||||
@@ -21,11 +22,20 @@ export default connect(mapStateToProps)(props => {
|
||||
<h3>{props.name}</h3>
|
||||
</td>
|
||||
<td>
|
||||
{props.AllowDownload ?
|
||||
<a href={'#'}
|
||||
className={'DependencyLink'}
|
||||
onClick={()=>{props.onDownload(); return false;}}><u>Install</u></a> :
|
||||
'Installing...'}
|
||||
{props.AllowDownload ? (
|
||||
<a
|
||||
href={'#'}
|
||||
className={'DependencyLink'}
|
||||
onClick={() => {
|
||||
props.onDownload();
|
||||
return false;
|
||||
}}
|
||||
>
|
||||
<u>Install</u>
|
||||
</a>
|
||||
) : (
|
||||
'Installing...'
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
.DependencyList {
|
||||
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import './DependencyList.css';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Constants from '../../constants';
|
||||
import Dependency from './Dependency/Dependency';
|
||||
import Box from '../UI/Box/Box';
|
||||
import {downloadItem} from '../../redux/actions/download_actions';
|
||||
import {extractFileNameFromURL} from '../../utils';
|
||||
import {setDismissDependencies} from '../../redux/actions/install_actions';
|
||||
import { downloadItem } from '../../redux/actions/download_actions';
|
||||
import { extractFileNameFromURL } from '../../utils.jsx';
|
||||
import { setDismissDependencies } from '../../redux/actions/install_actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
AllowDismissDependencies: state.relver.AllowDismissDependencies,
|
||||
MissingDependencies: state.install.MissingDependencies,
|
||||
@@ -17,33 +17,80 @@ const mapStateToProps = state => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
downloadItem: (name, type, url, isWinFSP) => dispatch(downloadItem(name, type, url, isWinFSP)),
|
||||
setDismissDependencies: dismiss => dispatch(setDismissDependencies(dismiss)),
|
||||
downloadItem: (name, type, url, isWinFSP) =>
|
||||
dispatch(downloadItem(name, type, url, isWinFSP)),
|
||||
setDismissDependencies: (dismiss) =>
|
||||
dispatch(setDismissDependencies(dismiss)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
const items = props.MissingDependencies.map((k, i)=> {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
const items = props.MissingDependencies.map((k, i) => {
|
||||
return (
|
||||
<Dependency key={i}
|
||||
name={k.display}
|
||||
onDownload={()=>props.downloadItem(extractFileNameFromURL(k.download), Constants.INSTALL_TYPES.Dependency, k.download, k.is_winfsp)}/>
|
||||
<Dependency
|
||||
key={i}
|
||||
name={k.display}
|
||||
onDownload={() =>
|
||||
props.downloadItem(
|
||||
extractFileNameFromURL(k.download),
|
||||
Constants.INSTALL_TYPES.Dependency,
|
||||
k.download,
|
||||
k.is_winfsp
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const dismissDisplay = (
|
||||
<div style={{float: 'right', margin: 0, paddingRight: '4px', boxSizing: 'border-box', display: 'block'}}>
|
||||
<a href={'#'}
|
||||
onClick={props.AllowDismissDependencies ? () => props.setDismissDependencies(true) : e => e.preventDefault()}
|
||||
style={{cursor: props.AllowDismissDependencies ? 'pointer' : 'no-drop'}}>X</a>
|
||||
<div
|
||||
style={{
|
||||
float: 'right',
|
||||
margin: 0,
|
||||
paddingRight: '4px',
|
||||
boxSizing: 'border-box',
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href={'#'}
|
||||
onClick={
|
||||
props.AllowDismissDependencies
|
||||
? () => props.setDismissDependencies(true)
|
||||
: (e) => e.preventDefault()
|
||||
}
|
||||
style={{
|
||||
cursor: props.AllowDismissDependencies ? 'pointer' : 'no-drop',
|
||||
}}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box dxStyle={{width: '300px', height: 'auto', padding: '5px'}}>
|
||||
<Box dxStyle={{ width: '300px', height: 'auto', padding: '5px' }}>
|
||||
{dismissDisplay}
|
||||
<div style={{width: '100%', height: 'auto', paddingBottom: '5px', boxSizing: 'border-box'}}>
|
||||
<h1 style={{width: '100%', textAlign: 'center', color: 'var(--text_color_error)'}}>Missing Dependencies</h1>
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
paddingBottom: '5px',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
<h1
|
||||
style={{
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
color: 'var(--text_color_error)',
|
||||
}}
|
||||
>
|
||||
Missing Dependencies
|
||||
</h1>
|
||||
</div>
|
||||
{items}
|
||||
</Box>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Box from '../UI/Box/Box';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import React from 'react';
|
||||
import './DownloadProgress.css';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
DownloadName: state.download.DownloadName,
|
||||
DownloadProgress: state.download.DownloadProgress,
|
||||
@@ -11,15 +11,21 @@ const mapStateToProps = state => {
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(props => {
|
||||
export default connect(mapStateToProps)((props) => {
|
||||
const width = props.Platform === 'linux' ? '480px' : '380px';
|
||||
return (
|
||||
<Box dxStyle={{width: width, height: 'auto', padding: '5px'}}>
|
||||
<div style={{width: '100%', height: 'auto'}}>
|
||||
<h1 style={{width: '100%', textAlign: 'center'}}>{'Downloading ' + props.DownloadName}</h1>
|
||||
<Box dxStyle={{ width: width, height: 'auto', padding: '5px' }}>
|
||||
<div style={{ width: '100%', height: 'auto' }}>
|
||||
<h1 style={{ width: '100%', textAlign: 'center' }}>
|
||||
{'Downloading ' + props.DownloadName}
|
||||
</h1>
|
||||
</div>
|
||||
<progress max={100.0} id={'download_progress'}
|
||||
style={{width: '100%'}}
|
||||
value={props.DownloadProgress}/>
|
||||
</Box>);
|
||||
<progress
|
||||
max={100.0}
|
||||
id={'download_progress'}
|
||||
style={{ width: '100%' }}
|
||||
value={props.DownloadProgress}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
@@ -1,25 +1,29 @@
|
||||
import React from 'react';
|
||||
import {dismissError} from '../../redux/actions/error_actions';
|
||||
import {connect} from 'react-redux';
|
||||
import { dismissError } from '../../redux/actions/error_actions';
|
||||
import { connect } from 'react-redux';
|
||||
import Box from '../UI/Box/Box';
|
||||
import Button from '../UI/Button/Button';
|
||||
import './ErrorDetails.css';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
ErrorMessage: state.error.ErrorStack.length > 0 ? state.error.ErrorStack[0] : '',
|
||||
ErrorMessage:
|
||||
state.error.ErrorStack.length > 0 ? state.error.ErrorStack[0] : '',
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
dismissError: () => dispatch(dismissError()),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
return (
|
||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<h1 className={'ErrorDetailsHeading'}>Application Error</h1>
|
||||
<div className={'ErrorDetailsContent'}>
|
||||
<p>{props.ErrorMessage}</p>
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
import React from 'react';
|
||||
import {dismissInfo} from '../../redux/actions/error_actions';
|
||||
import {connect} from 'react-redux';
|
||||
import { dismissInfo } from '../../redux/actions/error_actions';
|
||||
import { connect } from 'react-redux';
|
||||
import Box from '../UI/Box/Box';
|
||||
import Button from '../UI/Button/Button';
|
||||
import './InfoDetails.css';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
InfoMessage: state.error.InfoStack.length > 0 ? state.error.InfoStack[0] : '',
|
||||
InfoMessage:
|
||||
state.error.InfoStack.length > 0 ? state.error.InfoStack[0] : '',
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
dismissInfo: () => dispatch(dismissInfo()),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
let msg = props.InfoMessage.message;
|
||||
const classes = ['InfoDetailsContent'];
|
||||
|
||||
@@ -37,7 +41,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
}
|
||||
}
|
||||
|
||||
const scrollToTop = textArea => {
|
||||
const scrollToTop = (textArea) => {
|
||||
if (!textArea.firstClick) {
|
||||
textArea.firstClick = true;
|
||||
textArea.scrollTop = 0;
|
||||
@@ -46,20 +50,20 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<h1 className={'InfoDetailsHeading'}>{props.InfoMessage.title}</h1>
|
||||
<div className={classes.join(' ')}>
|
||||
{
|
||||
copyable ? (
|
||||
<textarea autoFocus
|
||||
rows={9}
|
||||
value={msg}
|
||||
className={'SkynetImportTextArea'}
|
||||
onClick={e => scrollToTop(e.target)}/>
|
||||
) : (
|
||||
<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>
|
||||
<Button clicked={props.dismissInfo}>Dismiss</Button>
|
||||
</Box>
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import * as Constants from '../../../constants';
|
||||
import Button from '../../UI/Button/Button';
|
||||
import {formatLinesForDisplay, getChangesForRepertoryVersion} from '../../../utils';
|
||||
import {
|
||||
notifyError,
|
||||
notifyInfo
|
||||
} from '../../../redux/actions/error_actions';
|
||||
import {setActiveRelease} from '../../../redux/actions/release_version_actions';
|
||||
import {unmountAll} from '../../../redux/actions/mount_actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
ActiveRelease: state.relver.Release,
|
||||
ActiveVersion: state.relver.Version,
|
||||
}
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setActiveRelease: (release, version) => dispatch(setActiveRelease(release, version)),
|
||||
notifyError: msg => dispatch(notifyError(msg)),
|
||||
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
|
||||
unmountAll: completedCallback => dispatch(unmountAll(completedCallback)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(({
|
||||
ActiveRelease,
|
||||
ActiveVersion,
|
||||
dismiss,
|
||||
release,
|
||||
lastItem,
|
||||
notifyError,
|
||||
notifyInfo,
|
||||
setActiveRelease,
|
||||
unmountAll,
|
||||
}) => {
|
||||
const title = '[' + Constants.RELEASE_TYPES[release.Release] + '] ' + release.Display;
|
||||
const displayChanges = async () => {
|
||||
try {
|
||||
const lines = await getChangesForRepertoryVersion(release.VersionString);
|
||||
notifyInfo(title, formatLinesForDisplay(lines));
|
||||
} catch (e) {
|
||||
notifyError(e);
|
||||
}
|
||||
};
|
||||
|
||||
const isActiveRelease = ((release.Release === ActiveRelease) && (release.Version === ActiveVersion));
|
||||
const setReleaseAndVersion = () => {
|
||||
dismiss();
|
||||
unmountAll(() => {
|
||||
setActiveRelease(release.Release, release.Version);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>{title}</h2>
|
||||
<table cellSpacing={0} cellPadding={0} width="97%">
|
||||
<tbody>
|
||||
<tr style={{height: '4px'}}/>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<Button buttonStyles={{width: '100%'}} clicked={displayChanges}>Changes</Button>
|
||||
</td>
|
||||
<td>
|
||||
<div style={{width: 'var(--default_spacing)'}}/>
|
||||
</td>
|
||||
<td width="50%">
|
||||
{!isActiveRelease ?
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={setReleaseAndVersion}>Activate</Button>
|
||||
: null}
|
||||
</td>
|
||||
</tr>
|
||||
{lastItem ? null : <tr style={{height: 'var(--default_spacing)'}}/>}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
104
src/components/NewReleases/NewRelease/NewRelease.jsx
Normal file
104
src/components/NewReleases/NewRelease/NewRelease.jsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Constants from '../../../constants';
|
||||
import Button from '../../UI/Button/Button';
|
||||
import {
|
||||
formatLinesForDisplay,
|
||||
getChangesForRepertoryVersion,
|
||||
} from '../../../utils.jsx';
|
||||
import { notifyError, notifyInfo } from '../../../redux/actions/error_actions';
|
||||
import { setActiveRelease } from '../../../redux/actions/release_version_actions';
|
||||
import { unmountAll } from '../../../redux/actions/mount_actions';
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
ActiveRelease: state.relver.Release,
|
||||
ActiveVersion: state.relver.Version,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setActiveRelease: (release, version) =>
|
||||
dispatch(setActiveRelease(release, version)),
|
||||
notifyError: (msg) => dispatch(notifyError(msg)),
|
||||
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
|
||||
unmountAll: (completedCallback) => dispatch(unmountAll(completedCallback)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
({
|
||||
ActiveRelease,
|
||||
ActiveVersion,
|
||||
dismiss,
|
||||
release,
|
||||
lastItem,
|
||||
notifyError,
|
||||
notifyInfo,
|
||||
setActiveRelease,
|
||||
unmountAll,
|
||||
}) => {
|
||||
const title =
|
||||
'[' + Constants.RELEASE_TYPES[release.Release] + '] ' + release.Display;
|
||||
const displayChanges = async () => {
|
||||
try {
|
||||
const lines = await getChangesForRepertoryVersion(
|
||||
release.VersionString
|
||||
);
|
||||
notifyInfo(title, formatLinesForDisplay(lines));
|
||||
} catch (e) {
|
||||
notifyError(e);
|
||||
}
|
||||
};
|
||||
|
||||
const isActiveRelease =
|
||||
release.Release === ActiveRelease && release.Version === ActiveVersion;
|
||||
const setReleaseAndVersion = () => {
|
||||
dismiss();
|
||||
unmountAll(() => {
|
||||
setActiveRelease(release.Release, release.Version);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>{title}</h2>
|
||||
<table cellSpacing={0} cellPadding={0} width="97%">
|
||||
<tbody>
|
||||
<tr style={{ height: '4px' }} />
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={displayChanges}
|
||||
>
|
||||
Changes
|
||||
</Button>
|
||||
</td>
|
||||
<td>
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
</td>
|
||||
<td width="50%">
|
||||
{!isActiveRelease ? (
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={setReleaseAndVersion}
|
||||
>
|
||||
Activate
|
||||
</Button>
|
||||
) : null}
|
||||
</td>
|
||||
</tr>
|
||||
{lastItem ? null : (
|
||||
<tr style={{ height: 'var(--default_spacing)' }} />
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -1,38 +0,0 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import Box from '../UI/Box/Box';
|
||||
import Button from '../UI/Button/Button';
|
||||
import NewRelease from './NewRelease/NewRelease';
|
||||
import './NewReleases.css';
|
||||
import {setDismissNewReleasesAvailable} from '../../redux/actions/release_version_actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
NewReleasesAvailable: state.relver.NewReleasesAvailable,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
dismissNewReleasesAvailable: () => dispatch(setDismissNewReleasesAvailable(true)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
const newReleases = props.NewReleasesAvailable.map((i, idx) => {
|
||||
return <NewRelease dismiss={props.dismissNewReleasesAvailable}
|
||||
key={'new_release_' + i.Release + '_' + i.Version}
|
||||
lastItem={idx === (props.NewReleasesAvailable.length - 1)}
|
||||
release={i} />;
|
||||
});
|
||||
|
||||
return (
|
||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||
<h1 className={'NewReleasesHeading'}>New Repertory Versions Available</h1>
|
||||
<div className={'NewReleasesContent'}>
|
||||
{newReleases}
|
||||
</div>
|
||||
<Button clicked={props.dismissNewReleasesAvailable}>Dismiss</Button>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
44
src/components/NewReleases/NewReleases.jsx
Normal file
44
src/components/NewReleases/NewReleases.jsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Box from '../UI/Box/Box';
|
||||
import Button from '../UI/Button/Button';
|
||||
import NewRelease from './NewRelease/NewRelease.jsx';
|
||||
import './NewReleases.css';
|
||||
import { setDismissNewReleasesAvailable } from '../../redux/actions/release_version_actions';
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
NewReleasesAvailable: state.relver.NewReleasesAvailable,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
dismissNewReleasesAvailable: () =>
|
||||
dispatch(setDismissNewReleasesAvailable(true)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
const newReleases = props.NewReleasesAvailable.map((i, idx) => {
|
||||
return (
|
||||
<NewRelease
|
||||
dismiss={props.dismissNewReleasesAvailable}
|
||||
key={'new_release_' + i.Release + '_' + i.Version}
|
||||
lastItem={idx === props.NewReleasesAvailable.length - 1}
|
||||
release={i}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<h1 className={'NewReleasesHeading'}>New Repertory Versions Available</h1>
|
||||
<div className={'NewReleasesContent'}>{newReleases}</div>
|
||||
<Button clicked={props.dismissNewReleasesAvailable}>Dismiss</Button>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
@@ -1,24 +1,27 @@
|
||||
import React from 'react';
|
||||
import './Reboot.css';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import Box from '../UI/Box/Box';
|
||||
import Button from '../UI/Button/Button';
|
||||
import {rebootSystem} from '../../redux/actions/common_actions';
|
||||
import { rebootSystem } from '../../redux/actions/common_actions';
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
rebootSystem: () => dispatch(rebootSystem()),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(props => {
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
return (
|
||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<h1 className={'RebootHeading'}>Reboot System</h1>
|
||||
<div className={'RebootContent'}>
|
||||
<p>Repertory requires a system reboot to continue.</p>
|
||||
</div>
|
||||
<Button clicked={()=>props.rebootSystem()}>Reboot Now</Button>
|
||||
<Button clicked={() => props.rebootSystem()}>Reboot Now</Button>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
@@ -1,16 +1,16 @@
|
||||
import React from 'react';
|
||||
import './ReleaseVersionDisplay.css';
|
||||
import * as Constants from '../../constants';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import DropDown from '../UI/DropDown/DropDown';
|
||||
import Grid from '../UI/Grid/Grid';
|
||||
import Text from '../UI/Text/Text';
|
||||
import Button from '../UI/Button/Button';
|
||||
import UpgradeIcon from '../UpgradeIcon/UpgradeIcon';
|
||||
import {setActiveRelease} from '../../redux/actions/release_version_actions';
|
||||
import {downloadItem} from '../../redux/actions/download_actions';
|
||||
import { setActiveRelease } from '../../redux/actions/release_version_actions';
|
||||
import { downloadItem } from '../../redux/actions/download_actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
AllowMount: state.common.AllowMount,
|
||||
AppPlatform: state.common.AppPlatform,
|
||||
@@ -28,128 +28,170 @@ const mapStateToProps = state => {
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
downloadItem: (name, type, urls) => dispatch(downloadItem(name, type, urls)),
|
||||
setActiveRelease: (release, version) => dispatch(setActiveRelease(release, version)),
|
||||
}
|
||||
downloadItem: (name, type, urls) =>
|
||||
dispatch(downloadItem(name, type, urls)),
|
||||
setActiveRelease: (release, version) =>
|
||||
dispatch(setActiveRelease(release, version)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
const getSelectedVersion = () => {
|
||||
return (props.ReleaseVersion === -1) ?
|
||||
'unavailable' :
|
||||
props.VersionLookup[Constants.RELEASE_TYPES[props.Release]][props.ReleaseVersion];
|
||||
return props.ReleaseVersion === -1
|
||||
? 'unavailable'
|
||||
: props.VersionLookup[Constants.RELEASE_TYPES[props.Release]][
|
||||
props.ReleaseVersion
|
||||
];
|
||||
};
|
||||
|
||||
const handleDownloadRelease = () => {
|
||||
const fileName = props.version + '.zip';
|
||||
props.downloadItem(fileName, Constants.INSTALL_TYPES.Release, props.LocationsLookup[props.version].urls);
|
||||
props.downloadItem(
|
||||
fileName,
|
||||
Constants.INSTALL_TYPES.Release,
|
||||
props.LocationsLookup[props.version].urls
|
||||
);
|
||||
};
|
||||
|
||||
const handleReleaseChanged = e => {
|
||||
const handleReleaseChanged = (e) => {
|
||||
const release = Constants.RELEASE_TYPES.indexOf(e.target.value);
|
||||
const releaseVersion = props.VersionLookup[Constants.RELEASE_TYPES[release]].length - 1;
|
||||
const releaseVersion =
|
||||
props.VersionLookup[Constants.RELEASE_TYPES[release]].length - 1;
|
||||
props.setActiveRelease(release, releaseVersion);
|
||||
};
|
||||
|
||||
const handleVersionChanged = e => {
|
||||
const releaseVersion = props.VersionLookup[Constants.RELEASE_TYPES[props.Release]].indexOf(e.target.value);
|
||||
const handleVersionChanged = (e) => {
|
||||
const releaseVersion = props.VersionLookup[
|
||||
Constants.RELEASE_TYPES[props.Release]
|
||||
].indexOf(e.target.value);
|
||||
props.setActiveRelease(props.Release, releaseVersion);
|
||||
};
|
||||
|
||||
const text = props.InstalledVersion + ' [' + props.AppPlatform + ']';
|
||||
const disabled = props.DownloadActive ||
|
||||
const disabled =
|
||||
props.DownloadActive ||
|
||||
props.InstallActive ||
|
||||
props.MountsBusy ||
|
||||
(!props.AllowMount && (getSelectedVersion() !== 'unavailable')) ;
|
||||
const releaseExtracting = (props.InstallType === Constants.INSTALL_TYPES.Release);
|
||||
(!props.AllowMount && getSelectedVersion() !== 'unavailable');
|
||||
const releaseExtracting =
|
||||
props.InstallType === Constants.INSTALL_TYPES.Release;
|
||||
|
||||
let optionsDisplay = [];
|
||||
let key = 0;
|
||||
if (releaseExtracting) {
|
||||
optionsDisplay.push((
|
||||
<Text col={dimensions => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
rowSpan={4}
|
||||
text={'Activating'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
));
|
||||
optionsDisplay.push((
|
||||
<Text col={dimensions => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
text={text}
|
||||
textAlign={'left'}/>
|
||||
));
|
||||
optionsDisplay.push(
|
||||
<Text
|
||||
col={(dimensions) => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
rowSpan={4}
|
||||
text={'Activating'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
);
|
||||
optionsDisplay.push(
|
||||
<Text
|
||||
col={(dimensions) => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
text={text}
|
||||
textAlign={'left'}
|
||||
/>
|
||||
);
|
||||
} else if (props.downloadDisabled || props.DismissDependencies) {
|
||||
optionsDisplay.push((
|
||||
<Text col={dimensions => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
rowSpan={4}
|
||||
text={'Installed'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
));
|
||||
optionsDisplay.push(
|
||||
<Text
|
||||
col={(dimensions) => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
rowSpan={4}
|
||||
text={'Installed'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
);
|
||||
|
||||
optionsDisplay.push((
|
||||
<Text col={dimensions => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
text={text}
|
||||
textAlign={'left'}/>
|
||||
));
|
||||
optionsDisplay.push(
|
||||
<Text
|
||||
col={(dimensions) => (dimensions.columns / 3) * 2}
|
||||
colSpan={'remain'}
|
||||
key={key++}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
text={text}
|
||||
textAlign={'left'}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
optionsDisplay.push((
|
||||
<Button clicked={handleDownloadRelease}
|
||||
col={dimensions => (dimensions.columns / 3) * 2}
|
||||
colSpan={20}
|
||||
key={key++}
|
||||
row={5}
|
||||
rowSpan={7}>Install</Button>
|
||||
));
|
||||
optionsDisplay.push(
|
||||
<Button
|
||||
clicked={handleDownloadRelease}
|
||||
col={(dimensions) => (dimensions.columns / 3) * 2}
|
||||
colSpan={20}
|
||||
key={key++}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
>
|
||||
Install
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid noScroll>
|
||||
<Text colSpan={columns=>columns / 3}
|
||||
rowSpan={4}
|
||||
text={'Release'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<DropDown changed={handleReleaseChanged}
|
||||
colSpan={remain=>remain / 3 - 1}
|
||||
disabled={disabled}
|
||||
items={Constants.RELEASE_TYPES}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
selected={Constants.RELEASE_TYPES[props.Release]}/>
|
||||
<Text col={dimensions => dimensions.columns / 3}
|
||||
colSpan={remain=>remain / 2}
|
||||
rowSpan={4}
|
||||
text={'Version'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<UpgradeIcon available={props.ReleaseUpgradeAvailable}
|
||||
col={dimensions => ((dimensions.columns / 3) * 2) - 6}
|
||||
colSpan={4}
|
||||
release
|
||||
rowSpan={4}/>
|
||||
<DropDown changed={handleVersionChanged}
|
||||
col={dimensions => dimensions.columns / 3}
|
||||
colSpan={remain=>remain / 2 - 1}
|
||||
disabled={disabled}
|
||||
items={props.VersionLookup[Constants.RELEASE_TYPES[props.Release]]}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
selected={props.VersionLookup[Constants.RELEASE_TYPES[props.Release]][props.ReleaseVersion]}/>
|
||||
<Text
|
||||
colSpan={(columns) => columns / 3}
|
||||
rowSpan={4}
|
||||
text={'Release'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
<DropDown
|
||||
changed={handleReleaseChanged}
|
||||
colSpan={(remain) => remain / 3 - 1}
|
||||
disabled={disabled}
|
||||
items={Constants.RELEASE_TYPES}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
selected={Constants.RELEASE_TYPES[props.Release]}
|
||||
/>
|
||||
<Text
|
||||
col={(dimensions) => dimensions.columns / 3}
|
||||
colSpan={(remain) => remain / 2}
|
||||
rowSpan={4}
|
||||
text={'Version'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
<UpgradeIcon
|
||||
available={props.ReleaseUpgradeAvailable}
|
||||
col={(dimensions) => (dimensions.columns / 3) * 2 - 6}
|
||||
colSpan={4}
|
||||
release
|
||||
rowSpan={4}
|
||||
/>
|
||||
<DropDown
|
||||
changed={handleVersionChanged}
|
||||
col={(dimensions) => dimensions.columns / 3}
|
||||
colSpan={(remain) => remain / 2 - 1}
|
||||
disabled={disabled}
|
||||
items={props.VersionLookup[Constants.RELEASE_TYPES[props.Release]]}
|
||||
row={5}
|
||||
rowSpan={7}
|
||||
selected={
|
||||
props.VersionLookup[Constants.RELEASE_TYPES[props.Release]][
|
||||
props.ReleaseVersion
|
||||
]
|
||||
}
|
||||
/>
|
||||
{optionsDisplay}
|
||||
</Grid>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import './Box.css';
|
||||
|
||||
const Box = props => {
|
||||
const Box = (props) => {
|
||||
const styleList = [];
|
||||
styleList.push('Box');
|
||||
if (props.dxDark) {
|
||||
@@ -20,7 +20,8 @@ const Box = props => {
|
||||
<div
|
||||
onClick={props.clicked}
|
||||
className={styleList.join(' ')}
|
||||
style={{...props.dxStyle}}>
|
||||
style={{ ...props.dxStyle }}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import React from 'react';
|
||||
import './Button.css';
|
||||
|
||||
const Button = props => {
|
||||
const Button = (props) => {
|
||||
return (
|
||||
<button disabled={props.disabled}
|
||||
autoFocus={props.autoFocus}
|
||||
className={'Button'}
|
||||
style={props.buttonStyles}
|
||||
onClick={props.clicked}>{props.children}</button>
|
||||
<button
|
||||
disabled={props.disabled}
|
||||
autoFocus={props.autoFocus}
|
||||
className={'Button'}
|
||||
style={props.buttonStyles}
|
||||
onClick={props.clicked}
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ label.CheckBoxLabel {
|
||||
}
|
||||
|
||||
/* Hide the browser's default checkbox */
|
||||
label.CheckBoxLabel input[type=checkbox] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
label.CheckBoxLabel input[type='checkbox'] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
/* Create a custom checkbox */
|
||||
@@ -41,8 +41,8 @@ label.CheckBoxLabel input[type=checkbox] {
|
||||
}
|
||||
|
||||
/* On mouse-over, add a grey background color */
|
||||
label.CheckBoxLabel:hover input[type=checkbox] ~ .CheckBoxCheckMark {
|
||||
background-color: var(--control_background_hover);
|
||||
label.CheckBoxLabel:hover input[type='checkbox'] ~ .CheckBoxCheckMark {
|
||||
background-color: var(--control_background_hover);
|
||||
}
|
||||
|
||||
/* When the checkbox is checked, add a blue background */
|
||||
@@ -52,9 +52,9 @@ label.CheckBoxLabel input:checked ~ .CheckBoxCheckMark {
|
||||
|
||||
/* Create the CheckBoxCheckMark/indicator (hidden when not checked) */
|
||||
.CheckBoxCheckMark:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Show the CheckBoxCheckMark when checked */
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import React from 'react';
|
||||
import './CheckBox.css';
|
||||
|
||||
const CheckBox = props => {
|
||||
const CheckBox = (props) => {
|
||||
return (
|
||||
<div className={'CheckBoxOwner'}>
|
||||
<label className='CheckBoxLabel'>{props.label}
|
||||
<input checked={JSON.parse(props.checked)}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.disabled}
|
||||
onChange={props.changed}
|
||||
type='checkbox'/>
|
||||
<span className='CheckBoxCheckMark'/>
|
||||
<label className="CheckBoxLabel">
|
||||
{props.label}
|
||||
<input
|
||||
checked={JSON.parse(props.checked)}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.disabled}
|
||||
onChange={props.changed}
|
||||
type="checkbox"
|
||||
/>
|
||||
<span className="CheckBoxCheckMark" />
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -6,18 +6,19 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.DropDownSelect, .DropDownSelect.Alt {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
border-radius: var(--border_radius);
|
||||
background: var(--control_background);
|
||||
border: none;
|
||||
color: var(--text_color);
|
||||
box-sizing: border-box;
|
||||
outline: none !important;
|
||||
.DropDownSelect,
|
||||
.DropDownSelect.Alt {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
border-radius: var(--border_radius);
|
||||
background: var(--control_background);
|
||||
border: none;
|
||||
color: var(--text_color);
|
||||
box-sizing: border-box;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.DropDownSelect.Auto {
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
import React from 'react';
|
||||
import './DropDown.css';
|
||||
|
||||
const DropDown = props => {
|
||||
const DropDown = (props) => {
|
||||
const options = props.items.map((s, i) => {
|
||||
return (
|
||||
<option className={'DropDownOption'} key={i} value={s}>{s}</option>
|
||||
<option className={'DropDownOption'} key={i} value={s}>
|
||||
{s}
|
||||
</option>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={'DropDown'}>
|
||||
<select
|
||||
className={'DropDownSelect' + (props.auto ? ' Auto ' : '') + (props.alt ? ' Alt ' : '')}
|
||||
className={
|
||||
'DropDownSelect' +
|
||||
(props.auto ? ' Auto ' : '') +
|
||||
(props.alt ? ' Alt ' : '')
|
||||
}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.disabled}
|
||||
onChange={props.changed}
|
||||
value={props.selected}>
|
||||
value={props.selected}
|
||||
>
|
||||
{options}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
export default DropDown;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {Component} from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import './Grid.css';
|
||||
import GridComponent from './GridComponent/GridComponent';
|
||||
|
||||
@@ -10,14 +10,14 @@ export default class Grid extends Component {
|
||||
calculated: false,
|
||||
dimensions: {
|
||||
columns: 0,
|
||||
rows: 0
|
||||
}
|
||||
rows: 0,
|
||||
},
|
||||
};
|
||||
|
||||
calculateDimensions = size => {
|
||||
calculateDimensions = (size) => {
|
||||
return {
|
||||
columns: Math.floor(size.width / this.getGridSize()),
|
||||
rows: Math.floor(size.height / this.getGridSize())
|
||||
rows: Math.floor(size.height / this.getGridSize()),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class Grid extends Component {
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
clearInterval(this.resizeTimeout);
|
||||
};
|
||||
}
|
||||
|
||||
getGridSize = () => {
|
||||
return this.props.gridSize || DEFAULT_GRID_SIZE;
|
||||
@@ -43,7 +43,7 @@ export default class Grid extends Component {
|
||||
const elem = this.refs.GridOwner;
|
||||
return {
|
||||
height: elem ? elem.offsetHeight : 0,
|
||||
width: elem ? elem.offsetWidth : 0
|
||||
width: elem ? elem.offsetWidth : 0,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -54,15 +54,15 @@ export default class Grid extends Component {
|
||||
|
||||
updateSize = () => {
|
||||
const state = {
|
||||
...this.state
|
||||
...this.state,
|
||||
};
|
||||
const size = this.getSize();
|
||||
const dimensions = this.calculateDimensions(size);
|
||||
if (state.dimensions !== dimensions) {
|
||||
this.setState({
|
||||
calculated: true,
|
||||
dimensions: dimensions
|
||||
})
|
||||
dimensions: dimensions,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -79,34 +79,44 @@ export default class Grid extends Component {
|
||||
children = React.Children.map(this.props.children, (child, i) => {
|
||||
if (child) {
|
||||
let row = child.props.row || 0;
|
||||
if (typeof(row) === 'function') {
|
||||
if (typeof row === 'function') {
|
||||
row = row(dimensions);
|
||||
}
|
||||
|
||||
let col = child.props.col || 0;
|
||||
if (typeof(col) === 'function') {
|
||||
if (typeof col === 'function') {
|
||||
col = col(dimensions);
|
||||
}
|
||||
|
||||
let rowSpan = child.props.rowSpan;
|
||||
if (typeof(rowSpan) === 'function') {
|
||||
if (typeof rowSpan === 'function') {
|
||||
rowSpan = rowSpan(dimensions.rows - row, dimensions.rows);
|
||||
}
|
||||
|
||||
let colSpan = child.props.colSpan;
|
||||
if (typeof(colSpan) === 'function') {
|
||||
if (typeof colSpan === 'function') {
|
||||
colSpan = colSpan(dimensions.columns - col, dimensions.columns);
|
||||
}
|
||||
|
||||
rowSpan = rowSpan ? (rowSpan === 'remain' ? (dimensions.rows - row) : rowSpan) : null;
|
||||
colSpan = colSpan ? (colSpan === 'remain' ? dimensions.columns - col : colSpan) : null;
|
||||
rowSpan = rowSpan
|
||||
? rowSpan === 'remain'
|
||||
? dimensions.rows - row
|
||||
: rowSpan
|
||||
: null;
|
||||
colSpan = colSpan
|
||||
? colSpan === 'remain'
|
||||
? dimensions.columns - col
|
||||
: colSpan
|
||||
: null;
|
||||
|
||||
return (
|
||||
<GridComponent row={row}
|
||||
col={col}
|
||||
rowSpan={rowSpan}
|
||||
colSpan={colSpan}
|
||||
key={'gc_' + i}>
|
||||
<GridComponent
|
||||
row={row}
|
||||
col={col}
|
||||
rowSpan={rowSpan}
|
||||
colSpan={colSpan}
|
||||
key={'gc_' + i}
|
||||
>
|
||||
{child}
|
||||
</GridComponent>
|
||||
);
|
||||
@@ -123,7 +133,7 @@ export default class Grid extends Component {
|
||||
gridTemplateRows: gridSizePx.repeat(dimensions.rows),
|
||||
gridAutoColumns: gridSizePx,
|
||||
gridAutoRows: gridSizePx,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if (this.props.noScroll) {
|
||||
@@ -132,13 +142,11 @@ export default class Grid extends Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref='GridOwner'
|
||||
className={'GridOwner'}>
|
||||
<div ref="GridOwner" className={'GridOwner'}>
|
||||
<div className={'Grid'} {...style}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import './GridComponent.css';
|
||||
|
||||
const GridComponent = props => {
|
||||
const GridComponent = (props) => {
|
||||
const style = {
|
||||
style: {
|
||||
gridRowStart: Math.floor(props.row + 1),
|
||||
gridRowEnd: 'span ' + Math.floor(props.rowSpan || 1),
|
||||
gridColumnStart: Math.floor(props.col + 1),
|
||||
gridColumnEnd: 'span ' + Math.floor(props.colSpan || 1)
|
||||
}
|
||||
gridColumnEnd: 'span ' + Math.floor(props.colSpan || 1),
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -16,7 +16,6 @@ const GridComponent = props => {
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
export default GridComponent;
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
}
|
||||
|
||||
.LoadingContent {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
import React from 'react';
|
||||
import './Loading.css'
|
||||
import './Loading.css';
|
||||
import Loader from 'react-loader-spinner';
|
||||
|
||||
const Loading = () => {
|
||||
return (
|
||||
<div
|
||||
className={'Loading'}>
|
||||
<div className={'Loading'}>
|
||||
<div className={'LoadingContent'}>
|
||||
<Loader color={'var(--heading_text_color)'}
|
||||
height={28}
|
||||
width={28}
|
||||
type='ThreeDots'/>
|
||||
<Loader
|
||||
color={'var(--heading_text_color)'}
|
||||
height={28}
|
||||
width={28}
|
||||
type="ThreeDots"
|
||||
/>
|
||||
</div>
|
||||
</div>);
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Loading;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import './Modal.css'
|
||||
import './Modal.css';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
|
||||
const Modal = props => {
|
||||
const Modal = (props) => {
|
||||
let modalStyles = [];
|
||||
let contentStyles = [];
|
||||
modalStyles.push('Modal');
|
||||
@@ -19,12 +19,8 @@ const Modal = props => {
|
||||
|
||||
return (
|
||||
<FocusTrap active={!props.disableFocusTrap}>
|
||||
<div
|
||||
className={modalStyles.join(' ')}
|
||||
onClick={props.clicked}>
|
||||
<div className={contentStyles.join(' ')}>
|
||||
{props.children}
|
||||
</div>
|
||||
<div className={modalStyles.join(' ')} onClick={props.clicked}>
|
||||
<div className={contentStyles.join(' ')}>{props.children}</div>
|
||||
</div>
|
||||
</FocusTrap>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
const RootElem = props => {
|
||||
const RootElem = (props) => {
|
||||
return (
|
||||
<div style={{margin: 0, padding: 0}} {...props}>
|
||||
<div style={{ margin: 0, padding: 0 }} {...props}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default RootElem;
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
import React from 'react';
|
||||
import './Text.css';
|
||||
|
||||
const Text = props => {
|
||||
const Text = (props) => {
|
||||
const styleList = [];
|
||||
styleList.push('Text');
|
||||
if (props.type) {
|
||||
styleList.push('Text' + props.type);
|
||||
}
|
||||
|
||||
let style = {...props.style};
|
||||
let style = { ...props.style };
|
||||
if (props.textAlign) {
|
||||
style['textAlign'] = props.textAlign.toLowerCase();
|
||||
}
|
||||
|
||||
const text = (
|
||||
<div
|
||||
className={styleList.join(' ')}
|
||||
style={style}>{props.text}
|
||||
</div>);
|
||||
<div className={styleList.join(' ')} style={style}>
|
||||
{props.text}
|
||||
</div>
|
||||
);
|
||||
|
||||
return props.noOwner ? text : (
|
||||
<div className={'TextOwner'}>
|
||||
{text}
|
||||
</div>);
|
||||
return props.noOwner ? text : <div className={'TextOwner'}>{text}</div>;
|
||||
};
|
||||
|
||||
export default Text;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import './UpgradeIcon.css';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
import {faExclamationTriangle} from '@fortawesome/free-solid-svg-icons';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
|
||||
const UpgradeIcon = props => {
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import React from 'react';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
|
||||
const UpgradeIcon = (props) => {
|
||||
const styles = ['UpgradeIcon'];
|
||||
let placement = 'left';
|
||||
let toolTipText = 'UI Upgrade Available';
|
||||
@@ -17,21 +18,18 @@ const UpgradeIcon = props => {
|
||||
toolTipText = 'New Release Available';
|
||||
}
|
||||
|
||||
return props
|
||||
.available ?
|
||||
(
|
||||
<div className={'UpgradeIconOwner'}>
|
||||
<p data-tip='' data-for={placement}>
|
||||
<a href={'#'}
|
||||
className={styles.join(' ')}
|
||||
onClick={props.clicked}>
|
||||
<FontAwesomeIcon icon={faExclamationTriangle}/>
|
||||
</a>
|
||||
</p>
|
||||
<ReactTooltip id={placement} place={placement}>{toolTipText}</ReactTooltip>
|
||||
</div>
|
||||
)
|
||||
: null;
|
||||
return props.available ? (
|
||||
<div className={'UpgradeIconOwner'}>
|
||||
<p data-tip="" data-for={placement}>
|
||||
<a href={'#'} className={styles.join(' ')} onClick={props.clicked}>
|
||||
<FontAwesomeIcon icon={faExclamationTriangle} />
|
||||
</a>
|
||||
</p>
|
||||
<ReactTooltip id={placement} place={placement}>
|
||||
{toolTipText}
|
||||
</ReactTooltip>
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default UpgradeIcon;
|
||||
|
||||
@@ -1,55 +1,72 @@
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import Button from '../UI/Button/Button';
|
||||
import Box from '../UI/Box/Box';
|
||||
import * as Constants from '../../constants';
|
||||
import React from 'react';
|
||||
import './UpgradeUI.css';
|
||||
import {setDismissUIUpgrade} from '../../redux/actions/release_version_actions';
|
||||
import {downloadItem} from '../../redux/actions/download_actions';
|
||||
import { setDismissUIUpgrade } from '../../redux/actions/release_version_actions';
|
||||
import { downloadItem } from '../../redux/actions/download_actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
Platform: state.common.Platform,
|
||||
UpgradeData: state.relver.UpgradeData,
|
||||
UpgradeVersion: state.relver.UpgradeVersion,
|
||||
}
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
downloadItem: (name, type, urls) => dispatch(downloadItem(name, type, urls)),
|
||||
setDismissUIUpgrade: dismiss => dispatch(setDismissUIUpgrade(dismiss)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
downloadItem: (name, type, urls) =>
|
||||
dispatch(downloadItem(name, type, urls)),
|
||||
setDismissUIUpgrade: (dismiss) => dispatch(setDismissUIUpgrade(dismiss)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
const handleDownload = () => {
|
||||
const name = (props.Platform === 'win32') ?
|
||||
'upgrade.exe' :
|
||||
(props.Platform === 'darwin') ?
|
||||
'upgrade.dmg' :
|
||||
'repertory-ui_' + props.UpgradeVersion + '_linux_x86_64.AppImage';
|
||||
props.downloadItem(name, Constants.INSTALL_TYPES.Upgrade, props.UpgradeData.urls);
|
||||
const name =
|
||||
props.Platform === 'win32'
|
||||
? 'upgrade.exe'
|
||||
: props.Platform === 'darwin'
|
||||
? 'upgrade.dmg'
|
||||
: 'repertory-ui_' + props.UpgradeVersion + '_linux_x86_64.AppImage';
|
||||
props.downloadItem(
|
||||
name,
|
||||
Constants.INSTALL_TYPES.Upgrade,
|
||||
props.UpgradeData.urls
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box dxStyle={{width: '180px', height: 'auto', padding: '5px'}}>
|
||||
<div style={{width: '100%', height: 'auto'}}>
|
||||
<h1 style={{width: '100%', textAlign: 'center'}}>UI Upgrade Available</h1>
|
||||
<Box dxStyle={{ width: '180px', height: 'auto', padding: '5px' }}>
|
||||
<div style={{ width: '100%', height: 'auto' }}>
|
||||
<h1 style={{ width: '100%', textAlign: 'center' }}>
|
||||
UI Upgrade Available
|
||||
</h1>
|
||||
</div>
|
||||
<table cellSpacing={5} width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={handleDownload}>Install</Button>
|
||||
<Button buttonStyles={{ width: '100%' }} clicked={handleDownload}>
|
||||
Install
|
||||
</Button>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={() => props.setDismissUIUpgrade(true)}>Cancel</Button>
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={() => props.setDismissUIUpgrade(true)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Box>);
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
@@ -1,41 +1,59 @@
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import Button from '../UI/Button/Button';
|
||||
import Box from '../UI/Box/Box';
|
||||
import React from 'react';
|
||||
import './YesNo.css';
|
||||
import {hideConfirmYesNo} from '../../redux/actions/common_actions';
|
||||
import { hideConfirmYesNo } from '../../redux/actions/common_actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
Title: state.common.ConfirmTitle,
|
||||
}
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
hideConfirmYesNo: confirmed => dispatch(hideConfirmYesNo(confirmed)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
hideConfirmYesNo: (confirmed) => dispatch(hideConfirmYesNo(confirmed)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
return (
|
||||
<Box dxStyle={{minWidth: '180px', height: 'auto', padding: 'var(--default_spacing)'}}>
|
||||
<div style={{width: '100%', height: 'auto'}}>
|
||||
<h1 style={{width: '100%', textAlign: 'center'}}>{props.Title}</h1>
|
||||
<Box
|
||||
dxStyle={{
|
||||
minWidth: '180px',
|
||||
height: 'auto',
|
||||
padding: 'var(--default_spacing)',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: '100%', height: 'auto' }}>
|
||||
<h1 style={{ width: '100%', textAlign: 'center' }}>{props.Title}</h1>
|
||||
</div>
|
||||
<table cellSpacing={5} width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={() => props.hideConfirmYesNo(true)}>Yes</Button>
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={() => props.hideConfirmYesNo(true)}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={() => props.hideConfirmYesNo(false)}>No</Button>
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={() => props.hideConfirmYesNo(false)}
|
||||
>
|
||||
No
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Box>);
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
103
src/constants.js
103
src/constants.js
@@ -1,21 +1,21 @@
|
||||
Object.defineProperty(exports, '__esModule', {value : true});
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.DEV_PUBLIC_KEY =
|
||||
'-----BEGIN PUBLIC KEY-----\n' +
|
||||
'MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEKfZmq5mMAtD4kSt2Gc/5J\n' +
|
||||
'H+HHTYtUZE6YYvsvz8TNG/bNL67ZtNRyaoMyhLTfIN4rPBNLUfD+owNS+u5Yk+lS\n' +
|
||||
'ZLYyOuhoCZIFefayYqKLr42G8EeuRbx0IMzXmJtN0a4rqxlWhkYufJubpdQ+V4DF\n' +
|
||||
'oeupcPdIATaadCKVeZC7A0G0uaSwoiAVMG5dZqjQW7F2LoQm3PhNkPvAybIJ6vBy\n' +
|
||||
'LqdBegS1JrDn43x/pvQHzLO+l+FIG23D1F7iF+yZm3DkzBdcmi/mOMYs/rXZpBym\n' +
|
||||
'2/kTuSGh5buuJCeyOwR8N3WdvXw6+KHMU/wWU8qTCTT87mYbzH4YR8HgkjkLHxAO\n' +
|
||||
'5waHK6vMu0TxugCdJmVV6BSbiarJsh66VRosn7+6hlq6AdgksxqCeNELZBS+LBki\n' +
|
||||
'tb5hKyL+jNZnaHiR0U7USWtmnqZG6FVVRzlCnxP7tZo5O5Ex9AAFGz5JzOzsFNbv\n' +
|
||||
'xwQ0zqaTQOze+MJbkda7JfRoC6TncD0+3hoXsiaF4mCn8PqUCn0DwhglcRucZlST\n' +
|
||||
'ZvDNDo1WAtxPJebb3aS6uymNhBIquQbVAWxVO4eTrOYEgutxwkHE3yO3is+ogp8d\n' +
|
||||
'xot7f/+vzlbsbIDyuZBDe0fFkbTIMTU48QuUUVZpRKmKZTHQloz4EHqminbfX1sh\n' +
|
||||
'M7wvDkpJEtqbc0VnG/BukUzP6e7Skvgc7eF1sI3+8jH8du2rivZeZAl7Q2f+L9JA\n' +
|
||||
'BY9pjaxttxsud7V5jeFi4tKuDHi21/XhSjlJK2c2C4AiUEK5/WhtGbQ5JjmcOjRq\n' +
|
||||
'yXFRqLlerzOcop2kbtU3Ar230wOx3Dj23Wg8++lV3LU4U9vMR/t0qnSbCSGJys7m\n' +
|
||||
'ax2JpFlTwj/0wYuTlVFoNQHZJ1cdfyRiRBY4Ou7XO0W5hcBBKiYsC+neEeMMHdCe\n' +
|
||||
'-----BEGIN PUBLIC KEY-----\n' +
|
||||
'MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEKfZmq5mMAtD4kSt2Gc/5J\n' +
|
||||
'H+HHTYtUZE6YYvsvz8TNG/bNL67ZtNRyaoMyhLTfIN4rPBNLUfD+owNS+u5Yk+lS\n' +
|
||||
'ZLYyOuhoCZIFefayYqKLr42G8EeuRbx0IMzXmJtN0a4rqxlWhkYufJubpdQ+V4DF\n' +
|
||||
'oeupcPdIATaadCKVeZC7A0G0uaSwoiAVMG5dZqjQW7F2LoQm3PhNkPvAybIJ6vBy\n' +
|
||||
'LqdBegS1JrDn43x/pvQHzLO+l+FIG23D1F7iF+yZm3DkzBdcmi/mOMYs/rXZpBym\n' +
|
||||
'2/kTuSGh5buuJCeyOwR8N3WdvXw6+KHMU/wWU8qTCTT87mYbzH4YR8HgkjkLHxAO\n' +
|
||||
'5waHK6vMu0TxugCdJmVV6BSbiarJsh66VRosn7+6hlq6AdgksxqCeNELZBS+LBki\n' +
|
||||
'tb5hKyL+jNZnaHiR0U7USWtmnqZG6FVVRzlCnxP7tZo5O5Ex9AAFGz5JzOzsFNbv\n' +
|
||||
'xwQ0zqaTQOze+MJbkda7JfRoC6TncD0+3hoXsiaF4mCn8PqUCn0DwhglcRucZlST\n' +
|
||||
'ZvDNDo1WAtxPJebb3aS6uymNhBIquQbVAWxVO4eTrOYEgutxwkHE3yO3is+ogp8d\n' +
|
||||
'xot7f/+vzlbsbIDyuZBDe0fFkbTIMTU48QuUUVZpRKmKZTHQloz4EHqminbfX1sh\n' +
|
||||
'M7wvDkpJEtqbc0VnG/BukUzP6e7Skvgc7eF1sI3+8jH8du2rivZeZAl7Q2f+L9JA\n' +
|
||||
'BY9pjaxttxsud7V5jeFi4tKuDHi21/XhSjlJK2c2C4AiUEK5/WhtGbQ5JjmcOjRq\n' +
|
||||
'yXFRqLlerzOcop2kbtU3Ar230wOx3Dj23Wg8++lV3LU4U9vMR/t0qnSbCSGJys7m\n' +
|
||||
'ax2JpFlTwj/0wYuTlVFoNQHZJ1cdfyRiRBY4Ou7XO0W5hcBBKiYsC+neEeMMHdCe\n' +
|
||||
'iTDIW/ojcVTdFovl+sq3n1u4SBknE90JC/3H+TPE1s2iB+fwORVg0KPosQSNDS0A\n' +
|
||||
'7iK6AZCDC3YooFo+OzHkYMt9uLkXiXMSLx70az+qlIwOzVHKxCo7W/QpeKCXUCRZ\n' +
|
||||
'MMdlYEUs1PC8x2qIRUEVHuJ0XMTKNyOHmzVLuLK93wUWbToh+rdDxnbhX+emuESn\n' +
|
||||
@@ -32,19 +32,21 @@ const _REPERTORY_UI_BRANCH = '1.3.x_branch';
|
||||
exports.REPERTORY_BRANCH = _REPERTORY_BRANCH;
|
||||
exports.REPERTORY_UI_BRANCH = _REPERTORY_UI_BRANCH;
|
||||
|
||||
exports.RELEASES_URL = 'https://bitbucket.org/blockstorage/repertory/raw/' +
|
||||
_REPERTORY_BRANCH + '/releases_1.3.json';
|
||||
exports.RELEASES_URL =
|
||||
'https://bitbucket.org/blockstorage/repertory/raw/' +
|
||||
_REPERTORY_BRANCH +
|
||||
'/releases_1.3.json';
|
||||
exports.UI_RELEASES_URL =
|
||||
'https://bitbucket.org/blockstorage/repertory-ui/raw/' +
|
||||
_REPERTORY_UI_BRANCH + '/releases.json';
|
||||
_REPERTORY_UI_BRANCH +
|
||||
'/releases.json';
|
||||
|
||||
exports.LINUX_DETECT_SCRIPT_URL =
|
||||
'https://bitbucket.org/blockstorage/repertory/raw/' + _REPERTORY_BRANCH +
|
||||
'/detect_linux2.sh';
|
||||
'https://bitbucket.org/blockstorage/repertory/raw/' +
|
||||
_REPERTORY_BRANCH +
|
||||
'/detect_linux2.sh';
|
||||
|
||||
exports.LINUX_SELECTABLE_PLATFORMS = [
|
||||
'centos7',
|
||||
];
|
||||
exports.LINUX_SELECTABLE_PLATFORMS = ['centos7'];
|
||||
|
||||
exports.WINFSP_VERSION_NAMES = [
|
||||
'WinFsp 2019',
|
||||
@@ -68,55 +70,42 @@ exports.WINFSP_VERSION_NAMES = [
|
||||
];
|
||||
|
||||
exports.DATA_LOCATIONS = {
|
||||
linux : '~/.local/repertory/ui',
|
||||
darwin : '~/Library/Application Support/repertory/ui',
|
||||
win32 : '%LOCALAPPDATA%\\repertory\\ui'
|
||||
linux: '~/.local/repertory/ui',
|
||||
darwin: '~/Library/Application Support/repertory/ui',
|
||||
win32: '%LOCALAPPDATA%\\repertory\\ui',
|
||||
};
|
||||
|
||||
exports.REPERTORY_LOCATIONS = {
|
||||
linux : '~/.local/repertory',
|
||||
darwin : '~/Library/Application Support/repertory',
|
||||
win32 : '%LOCALAPPDATA%\\repertory'
|
||||
linux: '~/.local/repertory',
|
||||
darwin: '~/Library/Application Support/repertory',
|
||||
win32: '%LOCALAPPDATA%\\repertory',
|
||||
};
|
||||
|
||||
exports.S3_PROVIDER_LIST = [
|
||||
'Filebase',
|
||||
];
|
||||
exports.S3_PROVIDER_LIST = ['Filebase'];
|
||||
|
||||
exports.S3_REGION_PROVIDER_REGION = [
|
||||
'us-east-1',
|
||||
];
|
||||
exports.S3_REGION_PROVIDER_REGION = ['us-east-1'];
|
||||
|
||||
exports.S3_PROVIDER_URL = {
|
||||
'Filebase' : 'https://s3.filebase.com',
|
||||
Filebase: 'https://s3.filebase.com',
|
||||
};
|
||||
|
||||
exports.PROVIDER_LIST = [
|
||||
'Sia',
|
||||
'Skynet',
|
||||
'ScPrime',
|
||||
];
|
||||
exports.PROVIDER_LIST = ['Sia', 'Skynet', 'ScPrime'];
|
||||
|
||||
exports.PROVIDER_ARG = {
|
||||
sia : '',
|
||||
skynet : '-sk',
|
||||
scprime : '-sp',
|
||||
s3 : '-s3',
|
||||
sia: '',
|
||||
skynet: '-sk',
|
||||
scprime: '-sp',
|
||||
s3: '-s3',
|
||||
};
|
||||
|
||||
exports.DEFAULT_RELEASE = 0;
|
||||
exports.RELEASE_TYPES = [
|
||||
'Release',
|
||||
'RC',
|
||||
'Beta',
|
||||
'Alpha',
|
||||
];
|
||||
exports.RELEASE_TYPES = ['Release', 'RC', 'Beta', 'Alpha'];
|
||||
|
||||
exports.INSTALL_TYPES = {
|
||||
Dependency : 'dependency',
|
||||
Release : 'release',
|
||||
TestRelease : 'test_release',
|
||||
Upgrade : 'upgrade',
|
||||
Dependency: 'dependency',
|
||||
Release: 'release',
|
||||
TestRelease: 'test_release',
|
||||
Upgrade: 'upgrade',
|
||||
};
|
||||
|
||||
exports.IPC_Browse_Directory = 'browse_directory';
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
import React from 'react';
|
||||
import {Component} from 'react';
|
||||
import { Component } from 'react';
|
||||
import './AddMount.css';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import Text from '../../components/UI/Text/Text';
|
||||
import {notifyError} from '../../redux/actions/error_actions';
|
||||
import {addRemoteMount, addS3Mount} from '../../redux/actions/mount_actions';
|
||||
import {createModalConditionally} from '../../utils';
|
||||
import { notifyError } from '../../redux/actions/error_actions';
|
||||
import { addRemoteMount, addS3Mount } from '../../redux/actions/mount_actions';
|
||||
import { createModalConditionally } from '../../utils.jsx';
|
||||
import DropDown from '../../components/UI/DropDown/DropDown';
|
||||
import * as Constants from '../../constants';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
RemoteMounts: state.mounts.RemoteMounts,
|
||||
S3Mounts: state.mounts.S3Mounts,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
addRemoteMount: (hostNameOrIp, port, token) => dispatch(addRemoteMount(hostNameOrIp, port, token)),
|
||||
addS3Mount: (name, accessKey, secretKey, region, bucketName, url) => dispatch(addS3Mount(name, accessKey, secretKey, region, bucketName, url)),
|
||||
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
|
||||
}
|
||||
addRemoteMount: (hostNameOrIp, port, token) =>
|
||||
dispatch(addRemoteMount(hostNameOrIp, port, token)),
|
||||
addS3Mount: (name, accessKey, secretKey, region, bucketName, url) =>
|
||||
dispatch(addS3Mount(name, accessKey, secretKey, region, bucketName, url)),
|
||||
notifyError: (msg, critical, callback) =>
|
||||
dispatch(notifyError(msg, critical, callback)),
|
||||
};
|
||||
};
|
||||
|
||||
const default_state = {
|
||||
@@ -40,207 +43,288 @@ const default_state = {
|
||||
Token: '',
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(class extends Component {
|
||||
state = {
|
||||
...default_state,
|
||||
};
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
class extends Component {
|
||||
state = {
|
||||
...default_state,
|
||||
};
|
||||
|
||||
addRemoteMount = () => {
|
||||
if (this.state.HostNameOrIp.length === 0) {
|
||||
this.props.notifyError('Hostname or IP cannot be empty.');
|
||||
} else {
|
||||
const provider = 'Remote' + this.state.HostNameOrIp + ':' + this.state.Port;
|
||||
if (this.props.RemoteMounts.includes(provider)) {
|
||||
this.props.notifyError('Remote host already exists');
|
||||
addRemoteMount = () => {
|
||||
if (this.state.HostNameOrIp.length === 0) {
|
||||
this.props.notifyError('Hostname or IP cannot be empty.');
|
||||
} else {
|
||||
this.setState({
|
||||
DisplayRemote: false
|
||||
}, () => {
|
||||
this.props.addRemoteMount(this.state.HostNameOrIp, this.state.Port, this.state.Token);
|
||||
this.setState({
|
||||
...default_state,
|
||||
});
|
||||
});
|
||||
const provider =
|
||||
'Remote' + this.state.HostNameOrIp + ':' + this.state.Port;
|
||||
if (this.props.RemoteMounts.includes(provider)) {
|
||||
this.props.notifyError('Remote host already exists');
|
||||
} else {
|
||||
this.setState(
|
||||
{
|
||||
DisplayRemote: false,
|
||||
},
|
||||
() => {
|
||||
this.props.addRemoteMount(
|
||||
this.state.HostNameOrIp,
|
||||
this.state.Port,
|
||||
this.state.Token
|
||||
);
|
||||
this.setState({
|
||||
...default_state,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
addS3Mount = () => {
|
||||
if (this.state.Name.length === 0) {
|
||||
this.props.notifyError('Name cannot be empty.');
|
||||
} else if (this.state.AccessKey.length === 0) {
|
||||
this.props.notifyError('AccessKey cannot be empty.');
|
||||
} else if (this.state.SecretKey.length === 0) {
|
||||
this.props.notifyError('SecretKey cannot be empty.')
|
||||
} else {
|
||||
const provider = 'S3' + this.state.Name;
|
||||
if (this.props.S3Mounts.includes(provider)) {
|
||||
this.props.notifyError('Remote host already exists');
|
||||
addS3Mount = () => {
|
||||
if (this.state.Name.length === 0) {
|
||||
this.props.notifyError('Name cannot be empty.');
|
||||
} else if (this.state.AccessKey.length === 0) {
|
||||
this.props.notifyError('AccessKey cannot be empty.');
|
||||
} else if (this.state.SecretKey.length === 0) {
|
||||
this.props.notifyError('SecretKey cannot be empty.');
|
||||
} else {
|
||||
this.setState({
|
||||
DisplayS3: false
|
||||
}, () => {
|
||||
this.props.addS3Mount(this.state.Name, this.state.AccessKey, this.state.SecretKey,
|
||||
this.state.Region, this.state.BucketName, Constants.S3_PROVIDER_URL[this.state.Provider]);
|
||||
this.setState({
|
||||
...default_state,
|
||||
});
|
||||
});
|
||||
const provider = 'S3' + this.state.Name;
|
||||
if (this.props.S3Mounts.includes(provider)) {
|
||||
this.props.notifyError('Remote host already exists');
|
||||
} else {
|
||||
this.setState(
|
||||
{
|
||||
DisplayS3: false,
|
||||
},
|
||||
() => {
|
||||
this.props.addS3Mount(
|
||||
this.state.Name,
|
||||
this.state.AccessKey,
|
||||
this.state.SecretKey,
|
||||
this.state.Region,
|
||||
this.state.BucketName,
|
||||
Constants.S3_PROVIDER_URL[this.state.Provider]
|
||||
);
|
||||
this.setState({
|
||||
...default_state,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleAddS3Mount = () => {
|
||||
this.setState({
|
||||
DisplayRemote: false,
|
||||
DisplayS3: true,
|
||||
});
|
||||
};
|
||||
|
||||
handleAddRemoteMount = () => {
|
||||
this.setState({
|
||||
DisplayRemote: true,
|
||||
DisplayS3: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const displayAddRemote = createModalConditionally(
|
||||
this.state.DisplayRemote,
|
||||
<Box
|
||||
dxDark
|
||||
dxStyle={{
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
padding: 'var(--default_spacing)',
|
||||
}}
|
||||
>
|
||||
<h1
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
paddingBottom: 'var(--default_spacing)',
|
||||
}}
|
||||
>
|
||||
Add Remote Mount
|
||||
</h1>
|
||||
<Text text={'Hostname or IP'} textAlign={'left'} type={'Heading2'} />
|
||||
<input
|
||||
onChange={(e) =>
|
||||
this.setState({ HostNameOrIp: e.target.value.trim() })
|
||||
}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.HostNameOrIp}
|
||||
/>
|
||||
<div style={{ paddingTop: 'var(--default_spacing)' }} />
|
||||
<Text text={'Port'} textAlign={'left'} type={'Heading2'} />
|
||||
<input
|
||||
max={65535}
|
||||
min={1025}
|
||||
onChange={(e) => this.setState({ Port: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={this.state.Port}
|
||||
/>
|
||||
<div style={{ paddingTop: 'var(--default_spacing)' }} />
|
||||
<Text text={'Remote Token'} textAlign={'left'} type={'Heading2'} />
|
||||
<input
|
||||
onChange={(e) => this.setState({ Token: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.Token}
|
||||
/>
|
||||
<div style={{ paddingTop: 'var(--default_spacing)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={() => this.addRemoteMount()}
|
||||
>
|
||||
OK
|
||||
</Button>
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={() => this.setState({ DisplayRemote: false })}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const displayAddS3 = createModalConditionally(
|
||||
this.state.DisplayS3,
|
||||
<Box
|
||||
dxDark
|
||||
dxStyle={{
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
padding: 'var(--default_spacing)',
|
||||
}}
|
||||
>
|
||||
<h1
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
paddingBottom: 'var(--default_spacing)',
|
||||
}}
|
||||
>
|
||||
Add S3 Mount
|
||||
</h1>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text text={'Name'} textAlign={'left'} type={'Heading2'} />
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<Text text={'Provider'} textAlign={'left'} type={'Heading2'} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<input
|
||||
onChange={(e) => this.setState({ Name: e.target.value.trim() })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ width: '100%' }}
|
||||
type={'text'}
|
||||
value={this.state.Name}
|
||||
/>
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<DropDown
|
||||
changed={(e) => this.setState({ Provider: e.target.value })}
|
||||
items={Constants.S3_PROVIDER_LIST}
|
||||
selected={this.state.Provider}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ paddingTop: 'var(--default_spacing)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text
|
||||
text={'Bucket Name (optional)'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<Text text={'Region'} textAlign={'left'} type={'Heading2'} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<input
|
||||
onChange={(e) => this.setState({ BucketName: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ width: '100%' }}
|
||||
type={'text'}
|
||||
value={this.state.BucketName}
|
||||
/>
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<input
|
||||
onChange={(e) => this.setState({ Region: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.Region}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ paddingTop: 'var(--default_spacing)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text text={'Access Key'} textAlign={'left'} type={'Heading2'} />
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<Text text={'Secret Key'} textAlign={'left'} type={'Heading2'} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<input
|
||||
onChange={(e) => this.setState({ AccessKey: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.AccessKey}
|
||||
/>
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<input
|
||||
onChange={(e) => this.setState({ SecretKey: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.SecretKey}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ paddingTop: 'calc(var(--default_spacing) * 2)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<div style={{ width: '200%' }} />
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={() => this.addS3Mount()}
|
||||
>
|
||||
OK
|
||||
</Button>
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<Button
|
||||
buttonStyles={{ width: '100%' }}
|
||||
clicked={() => this.setState({ DisplayS3: false })}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={'AddMount'}>
|
||||
{displayAddRemote}
|
||||
{displayAddS3}
|
||||
<div className={'AddMountButtons'}>
|
||||
{this.props.remoteSupported ? (
|
||||
<Button
|
||||
className={'AddMountButton'}
|
||||
clicked={this.handleAddRemoteMount}
|
||||
>
|
||||
Add Remote Mount
|
||||
</Button>
|
||||
) : null}
|
||||
{this.props.remoteSupported && this.props.s3Supported ? (
|
||||
<div style={{ paddingRight: 'var(--default_spacing)' }} />
|
||||
) : null}
|
||||
{this.props.s3Supported ? (
|
||||
<Button
|
||||
className={'AddMountButton'}
|
||||
clicked={this.handleAddS3Mount}
|
||||
>
|
||||
Add S3 Mount
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
handleAddS3Mount = () => {
|
||||
this.setState({
|
||||
DisplayRemote: false,
|
||||
DisplayS3: true,
|
||||
});
|
||||
};
|
||||
|
||||
handleAddRemoteMount = () => {
|
||||
this.setState({
|
||||
DisplayRemote: true,
|
||||
DisplayS3: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const displayAddRemote = createModalConditionally(this.state.DisplayRemote, (
|
||||
<Box dxDark
|
||||
dxStyle={{width: 'auto', height: 'auto', padding: 'var(--default_spacing)'}}>
|
||||
<h1 style={{textAlign: 'center', paddingBottom: 'var(--default_spacing)'}}>Add Remote
|
||||
Mount</h1>
|
||||
<Text text={'Hostname or IP'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<input onChange={e => this.setState({HostNameOrIp: e.target.value.trim()})}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.HostNameOrIp}/>
|
||||
<div style={{paddingTop: 'var(--default_spacing)'}}/>
|
||||
<Text text={'Port'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<input max={65535}
|
||||
min={1025}
|
||||
onChange={e => this.setState({Port: e.target.value})}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={this.state.Port}/>
|
||||
<div style={{paddingTop: 'var(--default_spacing)'}}/>
|
||||
<Text text={'Remote Token'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<input onChange={e => this.setState({Token: e.target.value})}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.Token}/>
|
||||
<div style={{paddingTop: 'var(--default_spacing)'}}/>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={() => this.addRemoteMount()}>OK</Button>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={() => this.setState({DisplayRemote: false})}>Cancel</Button>
|
||||
</div>
|
||||
</Box>
|
||||
));
|
||||
|
||||
const displayAddS3 = createModalConditionally(this.state.DisplayS3, (
|
||||
<Box dxDark
|
||||
dxStyle={{width: 'auto', height: 'auto', padding: 'var(--default_spacing)'}}>
|
||||
<h1 style={{textAlign: 'center', paddingBottom: 'var(--default_spacing)'}}>Add S3
|
||||
Mount</h1>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<Text text={'Name'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<Text text={'Provider'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<input onChange={e => this.setState({Name: e.target.value.trim()})}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{width: '100%'}}
|
||||
type={'text'}
|
||||
value={this.state.Name}/>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<DropDown changed={e => this.setState({Provider: e.target.value})}
|
||||
items={Constants.S3_PROVIDER_LIST}
|
||||
selected={this.state.Provider}/>
|
||||
</div>
|
||||
<div style={{paddingTop: 'var(--default_spacing)'}}/>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<Text text={'Bucket Name (optional)'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<Text text={'Region'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<input onChange={e => this.setState({BucketName: e.target.value})}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{width: '100%'}}
|
||||
type={'text'}
|
||||
value={this.state.BucketName}/>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<input onChange={e => this.setState({Region: e.target.value})}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.Region}/>
|
||||
</div>
|
||||
<div style={{paddingTop: 'var(--default_spacing)'}}/>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<Text text={'Access Key'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<Text text={'Secret Key'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}/>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<input onChange={e => this.setState({AccessKey: e.target.value})}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.AccessKey}/>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<input onChange={e => this.setState({SecretKey: e.target.value})}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.SecretKey}/>
|
||||
</div>
|
||||
<div style={{paddingTop: 'calc(var(--default_spacing) * 2)'}}/>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<div style={{width: '200%'}}/>
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={() => this.addS3Mount()}>OK</Button>
|
||||
<div style={{paddingLeft: 'var(--default_spacing)'}}/>
|
||||
<Button buttonStyles={{width: '100%'}}
|
||||
clicked={() => this.setState({DisplayS3: false})}>Cancel</Button>
|
||||
</div>
|
||||
</Box>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className={'AddMount'}>
|
||||
{displayAddRemote}
|
||||
{displayAddS3}
|
||||
<div className={'AddMountButtons'}>
|
||||
{this.props.remoteSupported ?
|
||||
<Button className={'AddMountButton'}
|
||||
clicked={this.handleAddRemoteMount}>Add Remote Mount</Button> : null}
|
||||
{this.props.remoteSupported && this.props.s3Supported ?
|
||||
<div style={{paddingRight: 'var(--default_spacing)'}}/> : null}
|
||||
{this.props.s3Supported ?
|
||||
<Button className={'AddMountButton'}
|
||||
clicked={this.handleAddS3Mount}>Add S3 Mount</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import './Configuration.css';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import ConfigurationItem from './ConfigurationItem/ConfigurationItem';
|
||||
import Modal from '../../components/UI/Modal/Modal';
|
||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||
import {displayConfiguration} from '../../redux/actions/mount_actions';
|
||||
import {notifyError} from '../../redux/actions/error_actions';
|
||||
import {displayPinnedManager} from '../../redux/actions/pinned_manager_actions';
|
||||
import { displayConfiguration } from '../../redux/actions/mount_actions';
|
||||
import { notifyError } from '../../redux/actions/error_actions';
|
||||
import { displayPinnedManager } from '../../redux/actions/pinned_manager_actions';
|
||||
|
||||
const Constants = require('../../constants');
|
||||
|
||||
@@ -25,7 +25,7 @@ class Configuration extends IPCContainer {
|
||||
ItemList: [],
|
||||
Saving: false,
|
||||
ShowAdvanced: false,
|
||||
Template: {}
|
||||
Template: {},
|
||||
};
|
||||
|
||||
checkItemChanged = (itemA, itemB) => {
|
||||
@@ -33,7 +33,7 @@ class Configuration extends IPCContainer {
|
||||
if (itemA.value.length !== itemB.value.length) {
|
||||
return true;
|
||||
}
|
||||
return itemA.value.filter(i => !itemB.value.includes(i)).length !== 0;
|
||||
return itemA.value.filter((i) => !itemB.value.includes(i)).length !== 0;
|
||||
}
|
||||
return itemA.value !== itemB.value;
|
||||
};
|
||||
@@ -52,7 +52,9 @@ class Configuration extends IPCContainer {
|
||||
const changedObjectItems = [];
|
||||
let j = 0;
|
||||
for (const item of this.state.ObjectLookup[key]) {
|
||||
if (this.checkItemChanged(this.state.OriginalObjectLookup[key][j++], item)) {
|
||||
if (
|
||||
this.checkItemChanged(this.state.OriginalObjectLookup[key][j++], item)
|
||||
) {
|
||||
changedObjectItems.push(item);
|
||||
}
|
||||
}
|
||||
@@ -65,7 +67,7 @@ class Configuration extends IPCContainer {
|
||||
}
|
||||
}
|
||||
|
||||
if ((changedItems.length > 0) || changedObjectLookup) {
|
||||
if (changedItems.length > 0 || changedObjectLookup) {
|
||||
this.setState({
|
||||
ChangedItems: changedItems,
|
||||
ChangedObjectLookup: changedObjectLookup,
|
||||
@@ -77,9 +79,18 @@ class Configuration extends IPCContainer {
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
this.setRequestHandler(Constants.IPC_Get_Config_Template_Reply, this.onGetConfigTemplateReply);
|
||||
this.setRequestHandler(Constants.IPC_Get_Config_Reply, this.onGetConfigReply);
|
||||
this.setRequestHandler(Constants.IPC_Set_Config_Values_Reply, this.onSetConfigValuesReply);
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Get_Config_Template_Reply,
|
||||
this.onGetConfigTemplateReply
|
||||
);
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Get_Config_Reply,
|
||||
this.onGetConfigReply
|
||||
);
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Set_Config_Values_Reply,
|
||||
this.onSetConfigValuesReply
|
||||
);
|
||||
this.sendRequest(Constants.IPC_Get_Config_Template, {
|
||||
Provider: this.props.DisplayConfiguration,
|
||||
Remote: this.props.DisplayRemoteConfiguration,
|
||||
@@ -95,55 +106,57 @@ class Configuration extends IPCContainer {
|
||||
|
||||
createItemList = (config, template) => {
|
||||
const objectList = [];
|
||||
const itemList = Object
|
||||
.keys(config)
|
||||
.map(key => {
|
||||
return {
|
||||
advanced: template[key] ? template[key].advanced : false,
|
||||
hide_remote: template[key] ? template[key].hide_remote : false,
|
||||
label: key,
|
||||
remote: template[key] ? template[key].remote : false,
|
||||
type: template[key] ? template[key].type : null,
|
||||
value: (template[key] && (template[key].type === 'object')) ?
|
||||
config[key] :
|
||||
(template[key] && (template[key].type === 'string_array')) ?
|
||||
config[key] :
|
||||
config[key].toString(),
|
||||
};
|
||||
})
|
||||
.filter(i => {
|
||||
let ret = template[i.label];
|
||||
if (ret && (template[i.label].type === 'object')) {
|
||||
objectList.push(i);
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
const itemList = Object.keys(config)
|
||||
.map((key) => {
|
||||
return {
|
||||
advanced: template[key] ? template[key].advanced : false,
|
||||
hide_remote: template[key] ? template[key].hide_remote : false,
|
||||
label: key,
|
||||
remote: template[key] ? template[key].remote : false,
|
||||
type: template[key] ? template[key].type : null,
|
||||
value:
|
||||
template[key] && template[key].type === 'object'
|
||||
? config[key]
|
||||
: template[key] && template[key].type === 'string_array'
|
||||
? config[key]
|
||||
: config[key].toString(),
|
||||
};
|
||||
})
|
||||
.filter((i) => {
|
||||
let ret = template[i.label];
|
||||
if (ret && template[i.label].type === 'object') {
|
||||
objectList.push(i);
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
return {
|
||||
ObjectList: objectList,
|
||||
ItemList: itemList,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
handleItemChanged = (target, idx) => {
|
||||
const itemList = [
|
||||
...this.state.ItemList
|
||||
];
|
||||
itemList[idx].value = target.type === 'textarea' ? target.string_array : target.value.toString();
|
||||
const itemList = [...this.state.ItemList];
|
||||
itemList[idx].value =
|
||||
target.type === 'textarea'
|
||||
? target.string_array
|
||||
: target.value.toString();
|
||||
this.setState({
|
||||
ItemList: itemList
|
||||
ItemList: itemList,
|
||||
});
|
||||
};
|
||||
|
||||
handleObjectItemChanged = (target, name, idx) => {
|
||||
const itemList = [
|
||||
...this.state.ObjectLookup[name]
|
||||
];
|
||||
const itemList = [...this.state.ObjectLookup[name]];
|
||||
const objectLookup = {
|
||||
...this.state.ObjectLookup,
|
||||
};
|
||||
|
||||
itemList[idx].value = target.type === 'textarea' ? target.string_array : target.value.toString();
|
||||
itemList[idx].value =
|
||||
target.type === 'textarea'
|
||||
? target.string_array
|
||||
: target.value.toString();
|
||||
objectLookup[name] = itemList;
|
||||
this.setState({
|
||||
ObjectLookup: objectLookup,
|
||||
@@ -157,12 +170,19 @@ class Configuration extends IPCContainer {
|
||||
|
||||
let objectLookup = {};
|
||||
for (const obj of list.ObjectList) {
|
||||
const list2 = this.createItemList(obj.value, this.state.Template[obj.label].template);
|
||||
const list2 = this.createItemList(
|
||||
obj.value,
|
||||
this.state.Template[obj.label].template
|
||||
);
|
||||
objectLookup[obj.label] = list2.ItemList;
|
||||
}
|
||||
|
||||
const isRemoteMount = this.props.remoteSupported &&
|
||||
JSON.parse(objectLookup['RemoteMount'].find(s => s.label === 'IsRemoteMount').value);
|
||||
const isRemoteMount =
|
||||
this.props.remoteSupported &&
|
||||
JSON.parse(
|
||||
objectLookup['RemoteMount'].find((s) => s.label === 'IsRemoteMount')
|
||||
.value
|
||||
);
|
||||
if (isRemoteMount) {
|
||||
for (const obj of list.ObjectList) {
|
||||
if (obj.hide_remote) {
|
||||
@@ -172,15 +192,16 @@ class Configuration extends IPCContainer {
|
||||
}
|
||||
|
||||
const objectLookupCopy = JSON.parse(JSON.stringify(objectLookup));
|
||||
this.setState({
|
||||
IsRemoteMount: isRemoteMount,
|
||||
ItemList: list.ItemList,
|
||||
ObjectLookup: objectLookup,
|
||||
OriginalItemList: itemListCopy,
|
||||
OriginalObjectLookup: objectLookupCopy,
|
||||
}, () => {
|
||||
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
IsRemoteMount: isRemoteMount,
|
||||
ItemList: list.ItemList,
|
||||
ObjectLookup: objectLookup,
|
||||
OriginalItemList: itemListCopy,
|
||||
OriginalObjectLookup: objectLookupCopy,
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
} else {
|
||||
this.props.notifyError(arg.data.Error);
|
||||
}
|
||||
@@ -188,16 +209,19 @@ class Configuration extends IPCContainer {
|
||||
|
||||
onGetConfigTemplateReply = (event, arg) => {
|
||||
if (arg.data.Success) {
|
||||
this.setState({
|
||||
Template: arg.data.Template,
|
||||
}, () => {
|
||||
this.sendRequest(Constants.IPC_Get_Config, {
|
||||
Provider: this.props.DisplayConfiguration,
|
||||
Remote: this.props.DisplayRemoteConfiguration,
|
||||
S3: this.props.DisplayS3Configuration,
|
||||
Version: this.props.version,
|
||||
});
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
Template: arg.data.Template,
|
||||
},
|
||||
() => {
|
||||
this.sendRequest(Constants.IPC_Get_Config, {
|
||||
Provider: this.props.DisplayConfiguration,
|
||||
Remote: this.props.DisplayRemoteConfiguration,
|
||||
S3: this.props.DisplayS3Configuration,
|
||||
Version: this.props.version,
|
||||
});
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.props.notifyError(arg.data.Error, false, () => {
|
||||
if (this._isMounted) {
|
||||
@@ -212,77 +236,102 @@ class Configuration extends IPCContainer {
|
||||
};
|
||||
|
||||
saveAndClose = () => {
|
||||
this.setState({
|
||||
Saving: true,
|
||||
}, () => {
|
||||
const changedItems = [];
|
||||
for (const item of this.state.ChangedItems) {
|
||||
changedItems.push({
|
||||
Name: item.label,
|
||||
Value: item.type === 'string_array' ?
|
||||
item.value.join(';') :
|
||||
item.value,
|
||||
});
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
Saving: true,
|
||||
},
|
||||
() => {
|
||||
const changedItems = [];
|
||||
for (const item of this.state.ChangedItems) {
|
||||
changedItems.push({
|
||||
Name: item.label,
|
||||
Value:
|
||||
item.type === 'string_array' ? item.value.join(';') : item.value,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.state.ChangedObjectLookup) {
|
||||
for (const key of Object.keys(this.state.ChangedObjectLookup)) {
|
||||
for (const item of this.state.ChangedObjectLookup[key]) {
|
||||
changedItems.push({
|
||||
Name: key + '.' + item.label,
|
||||
Value: item.type === 'string_array' ?
|
||||
item.value.join(';') :
|
||||
item.value,
|
||||
});
|
||||
if (this.state.ChangedObjectLookup) {
|
||||
for (const key of Object.keys(this.state.ChangedObjectLookup)) {
|
||||
for (const item of this.state.ChangedObjectLookup[key]) {
|
||||
changedItems.push({
|
||||
Name: key + '.' + item.label,
|
||||
Value:
|
||||
item.type === 'string_array'
|
||||
? item.value.join(';')
|
||||
: item.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.sendRequest(Constants.IPC_Set_Config_Values, {
|
||||
Items: changedItems,
|
||||
Provider: this.props.DisplayConfiguration,
|
||||
Remote: this.props.DisplayRemoteConfiguration,
|
||||
S3: this.props.DisplayS3Configuration,
|
||||
Version: this.props.version,
|
||||
});
|
||||
});
|
||||
this.sendRequest(Constants.IPC_Set_Config_Values, {
|
||||
Items: changedItems,
|
||||
Provider: this.props.DisplayConfiguration,
|
||||
Remote: this.props.DisplayRemoteConfiguration,
|
||||
S3: this.props.DisplayS3Configuration,
|
||||
Version: this.props.version,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
showRemoteConfigItem = (item, itemList) => {
|
||||
if (item.advanced &&
|
||||
if (
|
||||
item.advanced &&
|
||||
item.remote &&
|
||||
this.props.remoteSupported &&
|
||||
(item.label !== 'IsRemoteMount')) {
|
||||
const isRemoteMount = JSON.parse(itemList.find(s => s.label === 'IsRemoteMount').value);
|
||||
const enableRemoteMount = !isRemoteMount &&
|
||||
JSON.parse(itemList.find(s => s.label === 'EnableRemoteMount').value);
|
||||
return (item.label === 'RemoteHostNameOrIp') || (item.label === 'RemoteMaxConnections') ?
|
||||
isRemoteMount :
|
||||
(item.label === 'RemoteReceiveTimeoutSeconds') || (item.label === 'RemoteSendTimeoutSeconds') || (item.label === 'RemotePort') || (item.label === 'RemoteToken') ?
|
||||
isRemoteMount || enableRemoteMount :
|
||||
(item.label === 'EnableRemoteMount') ?
|
||||
!isRemoteMount :
|
||||
enableRemoteMount;
|
||||
item.label !== 'IsRemoteMount'
|
||||
) {
|
||||
const isRemoteMount = JSON.parse(
|
||||
itemList.find((s) => s.label === 'IsRemoteMount').value
|
||||
);
|
||||
const enableRemoteMount =
|
||||
!isRemoteMount &&
|
||||
JSON.parse(itemList.find((s) => s.label === 'EnableRemoteMount').value);
|
||||
return item.label === 'RemoteHostNameOrIp' ||
|
||||
item.label === 'RemoteMaxConnections'
|
||||
? isRemoteMount
|
||||
: item.label === 'RemoteReceiveTimeoutSeconds' ||
|
||||
item.label === 'RemoteSendTimeoutSeconds' ||
|
||||
item.label === 'RemotePort' ||
|
||||
item.label === 'RemoteToken'
|
||||
? isRemoteMount || enableRemoteMount
|
||||
: item.label === 'EnableRemoteMount'
|
||||
? !isRemoteMount
|
||||
: enableRemoteMount;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
render() {
|
||||
let confirmSave = null;
|
||||
if ((this.state.ChangedItems.length > 0) || this.state.ChangedObjectLookup) {
|
||||
if (this.state.ChangedItems.length > 0 || this.state.ChangedObjectLookup) {
|
||||
confirmSave = (
|
||||
<Modal>
|
||||
<Box dxStyle={{width: '40vw', padding: 'var(--default_spacing)'}}>
|
||||
<h1 style={{width: '100%', textAlign: 'center'}}>Save Changes?</h1>
|
||||
<table width='100%'>
|
||||
<Box dxStyle={{ width: '40vw', padding: 'var(--default_spacing)' }}>
|
||||
<h1 style={{ width: '100%', textAlign: 'center' }}>
|
||||
Save Changes?
|
||||
</h1>
|
||||
<table width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align='center' width='50%'><Button clicked={this.saveAndClose}
|
||||
disabled={this.state.Saving}>Yes</Button>
|
||||
</td>
|
||||
<td align='center' width='50%'><Button clicked={this.props.hideConfiguration}
|
||||
disabled={this.state.Saving}>No</Button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="50%">
|
||||
<Button
|
||||
clicked={this.saveAndClose}
|
||||
disabled={this.state.Saving}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</td>
|
||||
<td align="center" width="50%">
|
||||
<Button
|
||||
clicked={this.props.hideConfiguration}
|
||||
disabled={this.state.Saving}
|
||||
>
|
||||
No
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Box>
|
||||
@@ -294,84 +343,105 @@ class Configuration extends IPCContainer {
|
||||
|
||||
let objectItems = [];
|
||||
for (const key of Object.keys(this.state.ObjectLookup)) {
|
||||
objectItems.push((
|
||||
objectItems.push(
|
||||
<div key={key}>
|
||||
<h2>{key}</h2>
|
||||
<div>
|
||||
{
|
||||
this.state.ObjectLookup[key].map((k, i) => {
|
||||
const shouldFocus = autoFocus;
|
||||
autoFocus = false;
|
||||
return (
|
||||
(!k.advanced || (this.state.ShowAdvanced && k.advanced && !k.remote) || this.showRemoteConfigItem(k, this.state.ObjectLookup[key])) ?
|
||||
<ConfigurationItem advanced={k.advanced}
|
||||
autoFocus={shouldFocus}
|
||||
changed={e => this.handleObjectItemChanged(e, key, i)}
|
||||
grouping={key}
|
||||
items={this.state.Template[key].template[k.label].items}
|
||||
key={i}
|
||||
label={k.label}
|
||||
readOnly={this.state.IsRemoteMount && ((k.label === 'RemoteHostNameOrIp') || (k.label === 'RemotePort'))}
|
||||
template={this.state.Template[key].template[k.label]}
|
||||
value={k.value}/> :
|
||||
null)
|
||||
})
|
||||
}
|
||||
{this.state.ObjectLookup[key].map((k, i) => {
|
||||
const shouldFocus = autoFocus;
|
||||
autoFocus = false;
|
||||
return !k.advanced ||
|
||||
(this.state.ShowAdvanced && k.advanced && !k.remote) ||
|
||||
this.showRemoteConfigItem(k, this.state.ObjectLookup[key]) ? (
|
||||
<ConfigurationItem
|
||||
advanced={k.advanced}
|
||||
autoFocus={shouldFocus}
|
||||
changed={(e) => this.handleObjectItemChanged(e, key, i)}
|
||||
grouping={key}
|
||||
items={this.state.Template[key].template[k.label].items}
|
||||
key={i}
|
||||
label={k.label}
|
||||
readOnly={
|
||||
this.state.IsRemoteMount &&
|
||||
(k.label === 'RemoteHostNameOrIp' ||
|
||||
k.label === 'RemotePort')
|
||||
}
|
||||
template={this.state.Template[key].template[k.label]}
|
||||
value={k.value}
|
||||
/>
|
||||
) : null;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
const configurationItems = this.state.ItemList
|
||||
.map((k, i) => {
|
||||
const configurationItems = this.state.ItemList.map((k, i) => {
|
||||
const shouldFocus = autoFocus;
|
||||
autoFocus = false;
|
||||
return (
|
||||
((!this.state.IsRemoteMount || !k.hide_remote) && (!k.advanced || (this.state.ShowAdvanced && k.advanced))) ?
|
||||
<ConfigurationItem advanced={k.advanced}
|
||||
autoFocus={shouldFocus}
|
||||
changed={e => this.handleItemChanged(e, i)}
|
||||
grouping={'Settings'}
|
||||
items={this.state.Template[k.label].items}
|
||||
key={i}
|
||||
label={k.label}
|
||||
template={this.state.Template[k.label]}
|
||||
value={k.value}/> :
|
||||
null
|
||||
);
|
||||
return (!this.state.IsRemoteMount || !k.hide_remote) &&
|
||||
(!k.advanced || (this.state.ShowAdvanced && k.advanced)) ? (
|
||||
<ConfigurationItem
|
||||
advanced={k.advanced}
|
||||
autoFocus={shouldFocus}
|
||||
changed={(e) => this.handleItemChanged(e, i)}
|
||||
grouping={'Settings'}
|
||||
items={this.state.Template[k.label].items}
|
||||
key={i}
|
||||
label={k.label}
|
||||
template={this.state.Template[k.label]}
|
||||
value={k.value}
|
||||
/>
|
||||
) : null;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={'Configuration'}>
|
||||
{confirmSave}
|
||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||
<div style={{
|
||||
float: 'right',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
marginTop: '-4px',
|
||||
boxSizing: 'border-box',
|
||||
display: 'block'
|
||||
}}>
|
||||
<a href={'#'}
|
||||
onClick={this.checkSaveRequired}
|
||||
style={{cursor: 'pointer'}}>X</a>
|
||||
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<div
|
||||
style={{
|
||||
float: 'right',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
marginTop: '-4px',
|
||||
boxSizing: 'border-box',
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href={'#'}
|
||||
onClick={this.checkSaveRequired}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<h1 style={{width: '100%', textAlign: 'center'}}>{(
|
||||
this.props.DisplayRemoteConfiguration ?
|
||||
this.props.DisplayConfiguration.substr(6) :
|
||||
this.props.DisplayConfiguration) + ' Configuration '}
|
||||
<h1 style={{ width: '100%', textAlign: 'center' }}>
|
||||
{(this.props.DisplayRemoteConfiguration
|
||||
? this.props.DisplayConfiguration.substr(6)
|
||||
: this.props.DisplayConfiguration) + ' Configuration '}
|
||||
</h1>
|
||||
<div style={{overflowY: 'auto', height: '90%'}}>
|
||||
{this.props.MState.Mounted && (configurationItems.length > 0) ? <Button
|
||||
buttonStyles={{width: 'auto', height: 'auto', marginLeft: 'auto', marginRight: '4px'}}
|
||||
clicked={() => {
|
||||
this.props.displayPinnedManager(true);
|
||||
return false;
|
||||
}}> Pinned File Manager... </Button> : null}
|
||||
<div style={{marginBottom: '4px'}}/>
|
||||
<div style={{ overflowY: 'auto', height: '90%' }}>
|
||||
{this.props.MState.Mounted && configurationItems.length > 0 ? (
|
||||
<Button
|
||||
buttonStyles={{
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
marginLeft: 'auto',
|
||||
marginRight: '4px',
|
||||
}}
|
||||
clicked={() => {
|
||||
this.props.displayPinnedManager(true);
|
||||
return false;
|
||||
}}
|
||||
>
|
||||
Pinned File Manager...
|
||||
</Button>
|
||||
) : null}
|
||||
<div style={{ marginBottom: '4px' }} />
|
||||
{objectItems}
|
||||
{(configurationItems.length > 0) ? <h2>Settings</h2> : null}
|
||||
{configurationItems.length > 0 ? <h2>Settings</h2> : null}
|
||||
{configurationItems}
|
||||
</div>
|
||||
</Box>
|
||||
@@ -380,22 +450,23 @@ class Configuration extends IPCContainer {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
DisplayConfiguration: state.mounts.DisplayConfiguration,
|
||||
DisplayRemoteConfiguration: state.mounts.DisplayRemoteConfiguration,
|
||||
DisplayS3Configuration: state.mounts.DisplayS3Configuration,
|
||||
MState: state.mounts.MountState[state.mounts.DisplayConfiguration],
|
||||
Platform: state.common.Platform,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
displayPinnedManager: display => dispatch(displayPinnedManager(display)),
|
||||
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
|
||||
displayPinnedManager: (display) => dispatch(displayPinnedManager(display)),
|
||||
notifyError: (msg, critical, callback) =>
|
||||
dispatch(notifyError(msg, critical, callback)),
|
||||
hideConfiguration: () => dispatch(displayConfiguration(null, false)),
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Configuration);
|
||||
|
||||
@@ -29,7 +29,7 @@ textarea.ConfigurationItemInput {
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
overflow-y: scroll;
|
||||
overflow:-moz-scrollbars-horizontal;
|
||||
overflow: -moz-scrollbars-horizontal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
import React from 'react';
|
||||
import './ConfigurationItem.css';
|
||||
import CheckBox from '../../../components/UI/CheckBox/CheckBox';
|
||||
import {connect} from 'react-redux';
|
||||
import {faInfoCircle} from '@fortawesome/free-solid-svg-icons';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
notifyError,
|
||||
notifyInfo
|
||||
} from '../../../redux/actions/error_actions';
|
||||
import { connect } from 'react-redux';
|
||||
import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { notifyError, notifyInfo } from '../../../redux/actions/error_actions';
|
||||
import settings from '../../../assets/settings';
|
||||
import DropDown from '../../../components/UI/DropDown/DropDown';
|
||||
import Password from '../../../containers/UI/Password/Password';
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
notifyError: msg => dispatch(notifyError(msg)),
|
||||
notifyError: (msg) => dispatch(notifyError(msg)),
|
||||
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(props => {
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
const handleChanged = (e) => {
|
||||
const target = e.target;
|
||||
if (target.type === 'checkbox') {
|
||||
target.value = e.target.checked ? 'true' : 'false';
|
||||
} else if (target.type === 'textarea') {
|
||||
e.target.string_array = String(e.target.value).replace(/\r\n/g,'\n').split('\n');
|
||||
e.target.string_array = String(e.target.value)
|
||||
.replace(/\r\n/g, '\n')
|
||||
.split('\n');
|
||||
}
|
||||
props.changed(target);
|
||||
};
|
||||
@@ -37,137 +39,186 @@ export default connect(null, mapDispatchToProps)(props => {
|
||||
props.notifyInfo(props.label, description);
|
||||
};
|
||||
|
||||
infoDisplay = <a href={'#'}
|
||||
className={'ConfigurationInfo'}
|
||||
onClick={()=>{displayInfo(); return false;}}><FontAwesomeIcon icon={faInfoCircle}/></a>;
|
||||
infoDisplay = (
|
||||
<a
|
||||
href={'#'}
|
||||
className={'ConfigurationInfo'}
|
||||
onClick={() => {
|
||||
displayInfo();
|
||||
return false;
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faInfoCircle} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
let data;
|
||||
switch (props.template.type) {
|
||||
case 'bool':
|
||||
data = <CheckBox changed={handleChanged}
|
||||
checked={props.value}
|
||||
disabled={props.readOnly}
|
||||
autoFocus={props.autoFocus}/>;
|
||||
break;
|
||||
data = (
|
||||
<CheckBox
|
||||
changed={handleChanged}
|
||||
checked={props.value}
|
||||
disabled={props.readOnly}
|
||||
autoFocus={props.autoFocus}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'double':
|
||||
data = <input min={0.0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={e=>handleChanged(e)}
|
||||
step={'0.01'}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={parseFloat(props.value).toFixed(2)}/>;
|
||||
break;
|
||||
data = (
|
||||
<input
|
||||
min={0.0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={(e) => handleChanged(e)}
|
||||
step={'0.01'}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={parseFloat(props.value).toFixed(2)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'list':
|
||||
data = <DropDown alt
|
||||
auto
|
||||
autoFocus={props.autoFocus}
|
||||
changed={handleChanged}
|
||||
disabled={props.readOnly}
|
||||
items={props.items}
|
||||
selected={props.value} />;
|
||||
break;
|
||||
data = (
|
||||
<DropDown
|
||||
alt
|
||||
auto
|
||||
autoFocus={props.autoFocus}
|
||||
changed={handleChanged}
|
||||
disabled={props.readOnly}
|
||||
items={props.items}
|
||||
selected={props.value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
if (props.template.subtype === 'password') {
|
||||
data = (
|
||||
<Password autoFocus={props.autoFocus}
|
||||
changed={s => handleChanged({
|
||||
target: {
|
||||
type: 'password',
|
||||
value: s,
|
||||
},
|
||||
})}
|
||||
disabled={props.readOnly}
|
||||
mismatchHandler={() => props.notifyError('Passwords do not match')}
|
||||
value={props.value} />
|
||||
<Password
|
||||
autoFocus={props.autoFocus}
|
||||
changed={(s) =>
|
||||
handleChanged({
|
||||
target: {
|
||||
type: 'password',
|
||||
value: s,
|
||||
},
|
||||
})
|
||||
}
|
||||
disabled={props.readOnly}
|
||||
mismatchHandler={() => props.notifyError('Passwords do not match')}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
data = (
|
||||
<input onChange={e => handleChanged(e)}
|
||||
autoFocus={props.autoFocus}
|
||||
className={'ConfigurationItemInput'}
|
||||
disabled={props.readOnly}
|
||||
type={'text'}
|
||||
value={props.value}/>
|
||||
data = (
|
||||
<input
|
||||
onChange={(e) => handleChanged(e)}
|
||||
autoFocus={props.autoFocus}
|
||||
className={'ConfigurationItemInput'}
|
||||
disabled={props.readOnly}
|
||||
type={'text'}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'uint8':
|
||||
data = <input max={255}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={e=>handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}/>;
|
||||
break;
|
||||
data = (
|
||||
<input
|
||||
max={255}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={(e) => handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'uint16':
|
||||
data = <input max={65535}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={e=>handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}/>;
|
||||
break;
|
||||
data = (
|
||||
<input
|
||||
max={65535}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={(e) => handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'uint32':
|
||||
data = <input max={4294967295}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={e=>handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}/>;
|
||||
break;
|
||||
data = (
|
||||
<input
|
||||
max={4294967295}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={(e) => handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'uint64':
|
||||
data = <input max={18446744073709551615}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={e=>handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}/>;
|
||||
break;
|
||||
data = (
|
||||
<input
|
||||
max={18446744073709551615}
|
||||
min={0}
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={(e) => handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'number'}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'string_array':
|
||||
data = (
|
||||
<textarea autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
rows={4}
|
||||
cols={36}
|
||||
onChange={e=>handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
value={props.value.join('\n')} />
|
||||
<textarea
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
rows={4}
|
||||
cols={36}
|
||||
onChange={(e) => handleChanged(e)}
|
||||
className={'ConfigurationItemInput'}
|
||||
value={props.value.join('\n')}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'password':
|
||||
data = (
|
||||
<Password autoFocus={props.autoFocus}
|
||||
changed={s => handleChanged({
|
||||
target: {
|
||||
type: 'password',
|
||||
value: s,
|
||||
},
|
||||
})}
|
||||
disabled={props.readOnly}
|
||||
mismatchHandler={() => props.notifyError('Passwords do not match')}
|
||||
value={props.value} />
|
||||
<Password
|
||||
autoFocus={props.autoFocus}
|
||||
changed={(s) =>
|
||||
handleChanged({
|
||||
target: {
|
||||
type: 'password',
|
||||
value: s,
|
||||
},
|
||||
})
|
||||
}
|
||||
disabled={props.readOnly}
|
||||
mismatchHandler={() => props.notifyError('Passwords do not match')}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
data = <div>{props.value}</div>;
|
||||
@@ -175,13 +226,18 @@ export default connect(null, mapDispatchToProps)(props => {
|
||||
|
||||
return (
|
||||
<div className={'ConfigurationItem'}>
|
||||
<table cellPadding='2'
|
||||
width='100%'>
|
||||
<table cellPadding="2" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
{infoDisplay ?
|
||||
<td width='100%' valign={'top'}>{infoDisplay} {props.label}</td> :
|
||||
<td width='100%' valign={'top'}>{props.label}</td>}
|
||||
{infoDisplay ? (
|
||||
<td width="100%" valign={'top'}>
|
||||
{infoDisplay} {props.label}
|
||||
</td>
|
||||
) : (
|
||||
<td width="100%" valign={'top'}>
|
||||
{props.label}
|
||||
</td>
|
||||
)}
|
||||
<td>{data}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component} from 'react';
|
||||
import {getIPCRenderer} from '../../utils';
|
||||
import { Component } from 'react';
|
||||
import { getIPCRenderer } from '../../utils.jsx';
|
||||
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
|
||||
@@ -16,7 +16,7 @@ export default class IPCContainer extends Component {
|
||||
}
|
||||
|
||||
this.handlerList = {};
|
||||
};
|
||||
}
|
||||
|
||||
sendRequest = (name, data) => {
|
||||
if (ipcRenderer) {
|
||||
@@ -41,5 +41,4 @@ export default class IPCContainer extends Component {
|
||||
ipcRenderer.on(name, callback);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import './MountItem.css';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import DropDown from '../../../components/UI/DropDown/DropDown';
|
||||
import Button from '../../../components/UI/Button/Button';
|
||||
import Loader from 'react-loader-spinner';
|
||||
@@ -11,36 +11,41 @@ import RootElem from '../../../components/UI/RootElem/RootElem';
|
||||
import {
|
||||
displayConfiguration,
|
||||
removeMount,
|
||||
setProviderState
|
||||
setProviderState,
|
||||
} from '../../../redux/actions/mount_actions';
|
||||
import {
|
||||
displaySkynetExport,
|
||||
displaySkynetImport,
|
||||
} from '../../../redux/actions/skynet_actions'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import { faTrashAlt} from '@fortawesome/free-solid-svg-icons';
|
||||
} from '../../../redux/actions/skynet_actions';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import CheckBox from '../../../components/UI/CheckBox/CheckBox';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
MState: state.mounts.MountState[ownProps.provider],
|
||||
Platform: state.common.Platform,
|
||||
PState: state.mounts.ProviderState[ownProps.provider]
|
||||
PState: state.mounts.ProviderState[ownProps.provider],
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
displayConfiguration: (provider, remote, s3) => dispatch(displayConfiguration(provider, remote, s3)),
|
||||
displaySkynetExport: display => dispatch(displaySkynetExport(display)),
|
||||
displaySkynetImport: display => dispatch(displaySkynetImport(display)),
|
||||
removeMount: provider => dispatch(removeMount(provider)),
|
||||
setProviderState: (provider, state) => dispatch(setProviderState(provider, state)),
|
||||
}
|
||||
displayConfiguration: (provider, remote, s3) =>
|
||||
dispatch(displayConfiguration(provider, remote, s3)),
|
||||
displaySkynetExport: (display) => dispatch(displaySkynetExport(display)),
|
||||
displaySkynetImport: (display) => dispatch(displaySkynetImport(display)),
|
||||
removeMount: (provider) => dispatch(removeMount(provider)),
|
||||
setProviderState: (provider, state) =>
|
||||
dispatch(setProviderState(provider, state)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
const handleAutoMountChanged = e => {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((props) => {
|
||||
const handleAutoMountChanged = (e) => {
|
||||
const state = {
|
||||
...props.PState,
|
||||
AutoMount: e.target.checked,
|
||||
@@ -48,7 +53,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
props.setProviderState(props.provider, state);
|
||||
};
|
||||
|
||||
const handleAutoRestartChanged = e => {
|
||||
const handleAutoRestartChanged = (e) => {
|
||||
const state = {
|
||||
...props.PState,
|
||||
AutoRestart: e.target.checked,
|
||||
@@ -57,18 +62,28 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
};
|
||||
|
||||
let secondRow = 6;
|
||||
const pointer = {cursor: props.MState.AllowMount ? 'pointer' : 'no-drop'};
|
||||
const pointer = { cursor: props.MState.AllowMount ? 'pointer' : 'no-drop' };
|
||||
const configButton = (
|
||||
<RootElem colSpan={4}
|
||||
rowSpan={6}>
|
||||
<img alt=''
|
||||
height={'16px'}
|
||||
onClick={props.MState.AllowMount ? () => props.displayConfiguration(props.provider, props.remote, props.s3) : e => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
src={configureImage}
|
||||
style={{padding: 0, border: 0, margin: 0, ...pointer}}
|
||||
width={'16px'}/>
|
||||
<RootElem colSpan={4} rowSpan={6}>
|
||||
<img
|
||||
alt=""
|
||||
height={'16px'}
|
||||
onClick={
|
||||
props.MState.AllowMount
|
||||
? () =>
|
||||
props.displayConfiguration(
|
||||
props.provider,
|
||||
props.remote,
|
||||
props.s3
|
||||
)
|
||||
: (e) => {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
src={configureImage}
|
||||
style={{ padding: 0, border: 0, margin: 0, ...pointer }}
|
||||
width={'16px'}
|
||||
/>
|
||||
</RootElem>
|
||||
);
|
||||
|
||||
@@ -77,80 +92,119 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
if (props.Platform === 'win32') {
|
||||
inputColumnSpan = 20;
|
||||
const index = props.MState.DriveLetters.indexOf(props.PState.MountLocation);
|
||||
inputControls = <DropDown changed={props.changed}
|
||||
colSpan={inputColumnSpan}
|
||||
disabled={!props.MState.AllowMount || props.MState.Mounted}
|
||||
items={props.MState.DriveLetters}
|
||||
row={secondRow}
|
||||
rowSpan={7}
|
||||
selected={index >= 0 ? props.PState.MountLocation : ''}/>;
|
||||
|
||||
inputControls = (
|
||||
<DropDown
|
||||
changed={props.changed}
|
||||
colSpan={inputColumnSpan}
|
||||
disabled={!props.MState.AllowMount || props.MState.Mounted}
|
||||
items={props.MState.DriveLetters}
|
||||
row={secondRow}
|
||||
rowSpan={7}
|
||||
selected={index >= 0 ? props.PState.MountLocation : ''}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
inputColumnSpan = 64;
|
||||
inputControls = [];
|
||||
let key = 0;
|
||||
inputControls.push((
|
||||
<RootElem colSpan={inputColumnSpan - 8}
|
||||
key={'i' + key++}
|
||||
row={secondRow}
|
||||
rowSpan={7}>
|
||||
<input disabled={!props.MState.AllowMount || props.MState.Mounted}
|
||||
maxLength={4096}
|
||||
onChange={props.changed}
|
||||
size={4096}
|
||||
className={'MountItemInput'}
|
||||
type={'text'}
|
||||
value={props.PState.MountLocation}/>
|
||||
inputControls.push(
|
||||
<RootElem
|
||||
colSpan={inputColumnSpan - 8}
|
||||
key={'i' + key++}
|
||||
row={secondRow}
|
||||
rowSpan={7}
|
||||
>
|
||||
<input
|
||||
disabled={!props.MState.AllowMount || props.MState.Mounted}
|
||||
maxLength={4096}
|
||||
onChange={props.changed}
|
||||
size={4096}
|
||||
className={'MountItemInput'}
|
||||
type={'text'}
|
||||
value={props.PState.MountLocation}
|
||||
/>
|
||||
</RootElem>
|
||||
));
|
||||
inputControls.push((
|
||||
<Button clicked={()=>props.browseClicked(props.provider, props.PState.MountLocation)}
|
||||
col={inputColumnSpan - 7}
|
||||
colSpan={7}
|
||||
disabled={props.MState.Mounted || !props.MState.AllowMount}
|
||||
key={'b' + key++}
|
||||
row={secondRow}
|
||||
rowSpan={7}>...</Button>
|
||||
));
|
||||
);
|
||||
inputControls.push(
|
||||
<Button
|
||||
clicked={() =>
|
||||
props.browseClicked(props.provider, props.PState.MountLocation)
|
||||
}
|
||||
col={inputColumnSpan - 7}
|
||||
colSpan={7}
|
||||
disabled={props.MState.Mounted || !props.MState.AllowMount}
|
||||
key={'b' + key++}
|
||||
row={secondRow}
|
||||
rowSpan={7}
|
||||
>
|
||||
...
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
const buttonDisplay = props.MState.AllowMount ?
|
||||
(props.MState.Mounted ? 'Unmount' : 'Mount') :
|
||||
<Loader color={'var(--heading_text_color)'}
|
||||
height={19}
|
||||
type='Circles'
|
||||
width={19}/>;
|
||||
const buttonDisplay = props.MState.AllowMount ? (
|
||||
props.MState.Mounted ? (
|
||||
'Unmount'
|
||||
) : (
|
||||
'Mount'
|
||||
)
|
||||
) : (
|
||||
<Loader
|
||||
color={'var(--heading_text_color)'}
|
||||
height={19}
|
||||
type="Circles"
|
||||
width={19}
|
||||
/>
|
||||
);
|
||||
|
||||
const actionsDisplay = (
|
||||
<Button
|
||||
clicked={() => props.clicked(props.provider, props.remote, props.s3, !props.MState.Mounted, props.PState.MountLocation)}
|
||||
clicked={() =>
|
||||
props.clicked(
|
||||
props.provider,
|
||||
props.remote,
|
||||
props.s3,
|
||||
!props.MState.Mounted,
|
||||
props.PState.MountLocation
|
||||
)
|
||||
}
|
||||
col={inputColumnSpan + 2}
|
||||
colSpan={21}
|
||||
disabled={!props.MState.AllowMount}
|
||||
row={secondRow}
|
||||
rowSpan={7}>
|
||||
rowSpan={7}
|
||||
>
|
||||
{buttonDisplay}
|
||||
</Button>);
|
||||
</Button>
|
||||
);
|
||||
|
||||
const autoMountControl = (
|
||||
<RootElem col={inputColumnSpan + 24}
|
||||
colSpan={28}
|
||||
row={secondRow}
|
||||
rowSpan={7}>
|
||||
<CheckBox changed={handleAutoMountChanged}
|
||||
checked={props.PState.AutoMount}
|
||||
label={'Auto-mount'}/>
|
||||
<RootElem
|
||||
col={inputColumnSpan + 24}
|
||||
colSpan={28}
|
||||
row={secondRow}
|
||||
rowSpan={7}
|
||||
>
|
||||
<CheckBox
|
||||
changed={handleAutoMountChanged}
|
||||
checked={props.PState.AutoMount}
|
||||
label={'Auto-mount'}
|
||||
/>
|
||||
</RootElem>
|
||||
);
|
||||
|
||||
const autoRestartControl = (
|
||||
<RootElem col={inputColumnSpan + 24 + 28}
|
||||
colSpan={24}
|
||||
row={secondRow}
|
||||
rowSpan={7}>
|
||||
<CheckBox changed={handleAutoRestartChanged}
|
||||
checked={props.PState.AutoRestart}
|
||||
label={'Restart'}/>
|
||||
<RootElem
|
||||
col={inputColumnSpan + 24 + 28}
|
||||
colSpan={24}
|
||||
row={secondRow}
|
||||
rowSpan={7}
|
||||
>
|
||||
<CheckBox
|
||||
changed={handleAutoRestartChanged}
|
||||
checked={props.PState.AutoRestart}
|
||||
label={'Restart'}
|
||||
/>
|
||||
</RootElem>
|
||||
);
|
||||
|
||||
@@ -158,7 +212,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
if (props.allowRemove) {
|
||||
const removeDisabled = !props.MState.AllowMount || props.MState.Mounted;
|
||||
const removeStyle = {
|
||||
cursor: removeDisabled ? 'no-drop' : 'pointer'
|
||||
cursor: removeDisabled ? 'no-drop' : 'pointer',
|
||||
};
|
||||
const handleRemoveMount = () => {
|
||||
if (!removeDisabled) {
|
||||
@@ -166,17 +220,18 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
}
|
||||
};
|
||||
removeControl = (
|
||||
<RootElem col={dimensions=>dimensions.columns - 6}
|
||||
row={secondRow + 3}>
|
||||
<a href={'#'}
|
||||
onClick={handleRemoveMount}
|
||||
style={removeStyle}>
|
||||
<FontAwesomeIcon icon={faTrashAlt}/>
|
||||
<RootElem
|
||||
col={(dimensions) => dimensions.columns - 6}
|
||||
row={secondRow + 3}
|
||||
>
|
||||
<a href={'#'} onClick={handleRemoveMount} style={removeStyle}>
|
||||
<FontAwesomeIcon icon={faTrashAlt} />
|
||||
</a>
|
||||
</RootElem>);
|
||||
</RootElem>
|
||||
);
|
||||
}
|
||||
|
||||
const isSkynet = (props.provider === 'Skynet');
|
||||
const isSkynet = props.provider === 'Skynet';
|
||||
return (
|
||||
<div className={'MountItem'}>
|
||||
<Grid noScroll>
|
||||
@@ -185,28 +240,49 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
col={configButton ? 6 : 0}
|
||||
rowSpan={5}
|
||||
colSpan={90}
|
||||
text={props.remote ? props.provider.substr(6) : props.s3 ? props.provider.substr(2) : isSkynet ? props.provider + ' [EXPERIMENTAL]' : props.provider}
|
||||
text={
|
||||
props.remote
|
||||
? props.provider.substr(6)
|
||||
: props.s3
|
||||
? props.provider.substr(2)
|
||||
: isSkynet
|
||||
? props.provider + ' [EXPERIMENTAL]'
|
||||
: props.provider
|
||||
}
|
||||
textAlign={'Left'}
|
||||
type={'Heading2'}/>
|
||||
{(isSkynet && (props.MState.Mounted)) ? (
|
||||
<a href={'#'}
|
||||
col={(configButton ? 24 : 18) + 34}
|
||||
onClick={props.MState.AllowMount ? () => props.displaySkynetExport(true) : e => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
rowSpan={5}
|
||||
style={{...pointer, fontWeight: 'normal'}}>
|
||||
type={'Heading2'}
|
||||
/>
|
||||
{isSkynet && props.MState.Mounted ? (
|
||||
<a
|
||||
href={'#'}
|
||||
col={(configButton ? 24 : 18) + 34}
|
||||
onClick={
|
||||
props.MState.AllowMount
|
||||
? () => props.displaySkynetExport(true)
|
||||
: (e) => {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
rowSpan={5}
|
||||
style={{ ...pointer, fontWeight: 'normal' }}
|
||||
>
|
||||
<u>Export</u>
|
||||
</a>
|
||||
) : null}
|
||||
{(isSkynet && (props.MState.Mounted)) ? (
|
||||
<a href={'#'}
|
||||
col={(configButton ? 24 + 13 : 18 + 13) + 34}
|
||||
onClick={props.MState.AllowMount ? () => props.displaySkynetImport(true) : e => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
rowSpan={5}
|
||||
style={{...pointer, fontWeight: 'normal'}}>
|
||||
{isSkynet && props.MState.Mounted ? (
|
||||
<a
|
||||
href={'#'}
|
||||
col={(configButton ? 24 + 13 : 18 + 13) + 34}
|
||||
onClick={
|
||||
props.MState.AllowMount
|
||||
? () => props.displaySkynetImport(true)
|
||||
: (e) => {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
rowSpan={5}
|
||||
style={{ ...pointer, fontWeight: 'normal' }}
|
||||
>
|
||||
<u>Import</u>
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import AddMount from '../AddMount/AddMount';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import './MountItems.css';
|
||||
import Modal from '../../components/UI/Modal/Modal';
|
||||
import MountItem from './MountItem/MountItem';
|
||||
@@ -14,9 +14,9 @@ import {
|
||||
setBusy,
|
||||
setMounted,
|
||||
setMountState,
|
||||
setProviderState
|
||||
setProviderState,
|
||||
} from '../../redux/actions/mount_actions';
|
||||
import {notifyError} from '../../redux/actions/error_actions';
|
||||
import { notifyError } from '../../redux/actions/error_actions';
|
||||
|
||||
const Constants = require('../../constants');
|
||||
|
||||
@@ -29,7 +29,7 @@ class MountItems extends IPCContainer {
|
||||
RetryItems: {},
|
||||
};
|
||||
|
||||
addMountsBusy = provider => {
|
||||
addMountsBusy = (provider) => {
|
||||
this.props.setMountsBusy(true);
|
||||
this.activeDetections.push(provider);
|
||||
};
|
||||
@@ -43,22 +43,34 @@ class MountItems extends IPCContainer {
|
||||
...this.state.RetryItems,
|
||||
};
|
||||
delete retryItems[provider];
|
||||
this.setState({
|
||||
DisplayRetry: Object.keys(retryItems).length > 0,
|
||||
RetryItems: retryItems,
|
||||
}, () => {
|
||||
if (this.state.DisplayRetry) {
|
||||
this.sendRequest(Constants.IPC_Show_Window);
|
||||
this.setState(
|
||||
{
|
||||
DisplayRetry: Object.keys(retryItems).length > 0,
|
||||
RetryItems: retryItems,
|
||||
},
|
||||
() => {
|
||||
if (this.state.DisplayRetry) {
|
||||
this.sendRequest(Constants.IPC_Show_Window);
|
||||
}
|
||||
stateCallback();
|
||||
}
|
||||
stateCallback();
|
||||
});
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setRequestHandler(Constants.IPC_Detect_Mount_Reply, this.onDetectMountReply);
|
||||
this.setRequestHandler(Constants.IPC_Mount_Drive_Reply, this.onMountDriveReply);
|
||||
this.setRequestHandler(Constants.IPC_Unmount_Drive_Reply, this.onUnmountDriveReply);
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Detect_Mount_Reply,
|
||||
this.onDetectMountReply
|
||||
);
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Mount_Drive_Reply,
|
||||
this.onMountDriveReply
|
||||
);
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Unmount_Drive_Reply,
|
||||
this.onUnmountDriveReply
|
||||
);
|
||||
this.props.resetMountsState();
|
||||
this.detectMounts();
|
||||
}
|
||||
@@ -73,9 +85,9 @@ class MountItems extends IPCContainer {
|
||||
this.props.resetMountsState();
|
||||
this.activeDetections = [];
|
||||
super.componentWillUnmount();
|
||||
};
|
||||
}
|
||||
|
||||
detectMount = provider => {
|
||||
detectMount = (provider) => {
|
||||
this.addMountsBusy(provider);
|
||||
|
||||
this.sendRequest(Constants.IPC_Detect_Mount, {
|
||||
@@ -86,10 +98,10 @@ class MountItems extends IPCContainer {
|
||||
});
|
||||
};
|
||||
|
||||
detectMounts = ()=> {
|
||||
detectMounts = () => {
|
||||
if (!this.state.DisplayRetry) {
|
||||
const providerList = this.getProviderList();
|
||||
providerList.forEach(provider => {
|
||||
providerList.forEach((provider) => {
|
||||
this.detectMount(provider);
|
||||
});
|
||||
}
|
||||
@@ -98,7 +110,7 @@ class MountItems extends IPCContainer {
|
||||
displayRetryMount = (provider, remote, s3, mountLocation, msg) => {
|
||||
if (!this.state.RetryItems[provider]) {
|
||||
let retryItems = {
|
||||
...this.state.RetryItems
|
||||
...this.state.RetryItems,
|
||||
};
|
||||
retryItems[provider] = {
|
||||
RetrySeconds: 10,
|
||||
@@ -110,28 +122,37 @@ class MountItems extends IPCContainer {
|
||||
};
|
||||
this.props.setMountState(provider, mountState);
|
||||
|
||||
this.setState({
|
||||
DisplayRetry: true,
|
||||
RetryItems: retryItems,
|
||||
}, () => {
|
||||
this.sendRequest(Constants.IPC_Show_Window);
|
||||
this.retryIntervals[provider] = setInterval(() => {
|
||||
let retryItems = {
|
||||
...this.state.RetryItems,
|
||||
};
|
||||
const retrySeconds = retryItems[provider].RetrySeconds - 1;
|
||||
if (retrySeconds === 0) {
|
||||
this.cancelRetryMount(provider, () => {
|
||||
this.handleMountUnMount(provider, remote, s3, true, mountLocation);
|
||||
});
|
||||
} else {
|
||||
retryItems[provider].RetrySeconds = retrySeconds;
|
||||
this.setState({
|
||||
RetryItems: retryItems,
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
DisplayRetry: true,
|
||||
RetryItems: retryItems,
|
||||
},
|
||||
() => {
|
||||
this.sendRequest(Constants.IPC_Show_Window);
|
||||
this.retryIntervals[provider] = setInterval(() => {
|
||||
let retryItems = {
|
||||
...this.state.RetryItems,
|
||||
};
|
||||
const retrySeconds = retryItems[provider].RetrySeconds - 1;
|
||||
if (retrySeconds === 0) {
|
||||
this.cancelRetryMount(provider, () => {
|
||||
this.handleMountUnMount(
|
||||
provider,
|
||||
remote,
|
||||
s3,
|
||||
true,
|
||||
mountLocation
|
||||
);
|
||||
});
|
||||
} else {
|
||||
retryItems[provider].RetrySeconds = retrySeconds;
|
||||
this.setState({
|
||||
RetryItems: retryItems,
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -140,7 +161,7 @@ class MountItems extends IPCContainer {
|
||||
Title: provider + ' Mount Location',
|
||||
Location: location,
|
||||
});
|
||||
if (location && (location.length > 0)) {
|
||||
if (location && location.length > 0) {
|
||||
this.handleMountLocationChanged(provider, location);
|
||||
}
|
||||
};
|
||||
@@ -154,25 +175,29 @@ class MountItems extends IPCContainer {
|
||||
};
|
||||
|
||||
handleMountUnMount = (provider, remote, s3, mount, location) => {
|
||||
if (!location || (location.trim().length === 0)) {
|
||||
if (!location || location.trim().length === 0) {
|
||||
this.props.notifyError('Mount location is not set');
|
||||
} else {
|
||||
let allowAction = true;
|
||||
if (mount) {
|
||||
let result = remote || s3 || provider === 'Skynet' ?
|
||||
{Valid: true, Success: true} :
|
||||
this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, {
|
||||
Provider: provider,
|
||||
Remote: remote,
|
||||
S3: s3,
|
||||
Version: this.props.InstalledVersion
|
||||
}).data;
|
||||
let result =
|
||||
remote || s3 || provider === 'Skynet'
|
||||
? { Valid: true, Success: true }
|
||||
: this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, {
|
||||
Provider: provider,
|
||||
Remote: remote,
|
||||
S3: s3,
|
||||
Version: this.props.InstalledVersion,
|
||||
}).data;
|
||||
if (result.Success) {
|
||||
if (result.Valid) {
|
||||
if (this.props.Platform !== 'win32') {
|
||||
result = this.sendSyncRequest(Constants.IPC_Check_Mount_Location, {
|
||||
Location: location,
|
||||
});
|
||||
result = this.sendSyncRequest(
|
||||
Constants.IPC_Check_Mount_Location,
|
||||
{
|
||||
Location: location,
|
||||
}
|
||||
);
|
||||
if (!result.Success) {
|
||||
allowAction = false;
|
||||
this.props.notifyError(result.Error.toString());
|
||||
@@ -180,20 +205,56 @@ class MountItems extends IPCContainer {
|
||||
}
|
||||
} else {
|
||||
allowAction = false;
|
||||
if ((result.Code === new Uint32Array([-1])[0]) || (result.Code === new Uint8Array([-1])[0])) {
|
||||
this.displayRetryMount(provider, remote, s3, location, 'Failed to connect to ' + provider + ' daemon');
|
||||
} else if ((result.Code === new Uint32Array([-3])[0]) || (result.Code === new Uint8Array([-3])[0])) {
|
||||
this.displayRetryMount(provider, remote, s3, location, 'Incompatible ' + provider + ' daemon. Please upgrade ' + provider + '.');
|
||||
if (
|
||||
result.Code === new Uint32Array([-1])[0] ||
|
||||
result.Code === new Uint8Array([-1])[0]
|
||||
) {
|
||||
this.displayRetryMount(
|
||||
provider,
|
||||
remote,
|
||||
s3,
|
||||
location,
|
||||
'Failed to connect to ' + provider + ' daemon'
|
||||
);
|
||||
} else if (
|
||||
result.Code === new Uint32Array([-3])[0] ||
|
||||
result.Code === new Uint8Array([-3])[0]
|
||||
) {
|
||||
this.displayRetryMount(
|
||||
provider,
|
||||
remote,
|
||||
s3,
|
||||
location,
|
||||
'Incompatible ' +
|
||||
provider +
|
||||
' daemon. Please upgrade ' +
|
||||
provider +
|
||||
'.'
|
||||
);
|
||||
} else {
|
||||
this.displayRetryMount(provider, remote, s3, location, 'Version check failed: ' + result.Error);
|
||||
this.displayRetryMount(
|
||||
provider,
|
||||
remote,
|
||||
s3,
|
||||
location,
|
||||
'Version check failed: ' + result.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allowAction = false;
|
||||
if (this.props.Platform === 'win32') {
|
||||
this.props.notifyError('Failed to launch repertory. Please install Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019.');
|
||||
this.props.notifyError(
|
||||
'Failed to launch repertory. Please install Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019.'
|
||||
);
|
||||
} else {
|
||||
this.displayRetryMount(provider, remote, s3, location, 'Version check failed: ' + result.Error);
|
||||
this.displayRetryMount(
|
||||
provider,
|
||||
remote,
|
||||
s3,
|
||||
location,
|
||||
'Version check failed: ' + result.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,11 +284,13 @@ class MountItems extends IPCContainer {
|
||||
}
|
||||
};
|
||||
|
||||
getProviderList = providersOnly => {
|
||||
const providerList = Constants.PROVIDER_LIST.filter(i => {
|
||||
return ((i === 'Skynet') && this.props.skynetSupported) ||
|
||||
((i === 'ScPrime') && this.props.scPrimeSupported) ||
|
||||
((i === 'Sia') && this.props.siaSupported);
|
||||
getProviderList = (providersOnly) => {
|
||||
const providerList = Constants.PROVIDER_LIST.filter((i) => {
|
||||
return (
|
||||
(i === 'Skynet' && this.props.skynetSupported) ||
|
||||
(i === 'ScPrime' && this.props.scPrimeSupported) ||
|
||||
(i === 'Sia' && this.props.siaSupported)
|
||||
);
|
||||
});
|
||||
|
||||
let remoteList = [];
|
||||
@@ -240,17 +303,12 @@ class MountItems extends IPCContainer {
|
||||
s3List = [...this.props.S3Mounts];
|
||||
}
|
||||
|
||||
return [
|
||||
...providerList,
|
||||
...remoteList,
|
||||
...s3List,
|
||||
];
|
||||
return [...providerList, ...remoteList, ...s3List];
|
||||
};
|
||||
|
||||
hasActiveMount = () => {
|
||||
for (const provider of Object.keys(this.props.MountState)) {
|
||||
if (this.props.MountState[provider].Mounted)
|
||||
return true;
|
||||
if (this.props.MountState[provider].Mounted) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -259,7 +317,11 @@ class MountItems extends IPCContainer {
|
||||
onDetectMountReply = (event, arg) => {
|
||||
const provider = arg.data.Provider;
|
||||
if (!this.state.RetryItems[provider]) {
|
||||
if (arg.data.Success && (!arg.data.Active || (arg.data.Location && (arg.data.Location.length > 0)))) {
|
||||
if (
|
||||
arg.data.Success &&
|
||||
(!arg.data.Active ||
|
||||
(arg.data.Location && arg.data.Location.length > 0))
|
||||
) {
|
||||
const mountState = {
|
||||
AllowMount: true,
|
||||
DriveLetters: arg.data.DriveLetters,
|
||||
@@ -267,7 +329,12 @@ class MountItems extends IPCContainer {
|
||||
};
|
||||
this.props.setMountState(provider, mountState);
|
||||
|
||||
this.updateMountLocation(provider, arg.data.Location, mountState.Mounted, arg.data.DriveLetters);
|
||||
this.updateMountLocation(
|
||||
provider,
|
||||
arg.data.Location,
|
||||
mountState.Mounted,
|
||||
arg.data.DriveLetters
|
||||
);
|
||||
this.props.setAutoMountProcessed(provider, true);
|
||||
this.removeMountsBusy(provider);
|
||||
} else {
|
||||
@@ -284,39 +351,63 @@ class MountItems extends IPCContainer {
|
||||
};
|
||||
|
||||
onUnmountDriveReply = (event, arg) => {
|
||||
if (arg && arg.data && !arg.data.Expected && arg.data.Location && this.props.ProviderState[arg.data.Provider].AutoRestart) {
|
||||
this.displayRetryMount(arg.data.Provider, arg.data.Remote, arg.data.Location);
|
||||
if (
|
||||
arg &&
|
||||
arg.data &&
|
||||
!arg.data.Expected &&
|
||||
arg.data.Location &&
|
||||
this.props.ProviderState[arg.data.Provider].AutoRestart
|
||||
) {
|
||||
this.displayRetryMount(
|
||||
arg.data.Provider,
|
||||
arg.data.Remote,
|
||||
arg.data.Location
|
||||
);
|
||||
} else {
|
||||
this.detectMount(arg.data.Provider);
|
||||
}
|
||||
this.removeMountsBusy(arg.data.Provider);
|
||||
};
|
||||
|
||||
removeMountsBusy = provider => {
|
||||
removeMountsBusy = (provider) => {
|
||||
const idx = this.activeDetections.indexOf(provider);
|
||||
if (idx > -1) {
|
||||
this.activeDetections.splice(idx, 1);
|
||||
}
|
||||
this.props.setMountsBusy((this.activeDetections.length > 0) || this.hasActiveMount());
|
||||
this.props.setMountsBusy(
|
||||
this.activeDetections.length > 0 || this.hasActiveMount()
|
||||
);
|
||||
};
|
||||
|
||||
updateMountLocation = (provider, location, mounted, driveLetters) => {
|
||||
const providerState = this.props.ProviderState[provider];
|
||||
if (location.length === 0) {
|
||||
location = (this.props.Platform === 'win32') ?
|
||||
!providerState.MountLocation || providerState.MountLocation.trim().length === 0 ? driveLetters[0] : providerState.MountLocation :
|
||||
providerState.MountLocation;
|
||||
location =
|
||||
this.props.Platform === 'win32'
|
||||
? !providerState.MountLocation ||
|
||||
providerState.MountLocation.trim().length === 0
|
||||
? driveLetters[0]
|
||||
: providerState.MountLocation
|
||||
: providerState.MountLocation;
|
||||
}
|
||||
|
||||
if (location !== providerState.MountLocation) {
|
||||
this.handleMountLocationChanged(provider, location);
|
||||
}
|
||||
|
||||
if (!this.props.AutoMountProcessed[provider] &&
|
||||
if (
|
||||
!this.props.AutoMountProcessed[provider] &&
|
||||
this.props.ProviderState[provider].AutoMount &&
|
||||
!mounted &&
|
||||
(location.length > 0)) {
|
||||
this.handleMountUnMount(provider, this.props.RemoteMounts.includes(provider), this.props.S3Mounts.includes(provider), true, location);
|
||||
location.length > 0
|
||||
) {
|
||||
this.handleMountUnMount(
|
||||
provider,
|
||||
this.props.RemoteMounts.includes(provider),
|
||||
this.props.S3Mounts.includes(provider),
|
||||
true,
|
||||
location
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -328,104 +419,162 @@ class MountItems extends IPCContainer {
|
||||
for (const provider in this.state.RetryItems) {
|
||||
if (this.state.RetryItems.hasOwnProperty(provider)) {
|
||||
if (this.state.RetryItems[provider].RetryMessage) {
|
||||
retryList.push(<p key={'rl_' + retryList.length}>{this.state.RetryItems[provider].RetryMessage}</p>);
|
||||
retryList.push(
|
||||
<p key={'rl_' + retryList.length}>
|
||||
{this.state.RetryItems[provider].RetryMessage}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
retryList.push(<Button clicked={() => this.cancelRetryMount(provider, () => this.detectMounts())}
|
||||
key={'rl_' + retryList.length}>Cancel {provider} Remount
|
||||
({this.state.RetryItems[provider].RetrySeconds}s)</Button>);
|
||||
retryList.push(
|
||||
<Button
|
||||
clicked={() =>
|
||||
this.cancelRetryMount(provider, () => this.detectMounts())
|
||||
}
|
||||
key={'rl_' + retryList.length}
|
||||
>
|
||||
Cancel {provider} Remount (
|
||||
{this.state.RetryItems[provider].RetrySeconds}s)
|
||||
</Button>
|
||||
);
|
||||
if (++retryCount < Object.keys(this.state.RetryItems).length) {
|
||||
retryList.push(<div style={{paddingTop: 'var(--default_spacing)'}}
|
||||
key={'rl_' + retryList.length}/>);
|
||||
retryList.push(
|
||||
<div
|
||||
style={{ paddingTop: 'var(--default_spacing)' }}
|
||||
key={'rl_' + retryList.length}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retryDisplay = (
|
||||
<Modal>
|
||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)', minWidth: '70vw'}}>
|
||||
<h1 style={{
|
||||
textAlign: 'center',
|
||||
paddingBottom: 'var(--default_spacing)',
|
||||
color: 'var(--text_color_error)'
|
||||
}}>Mount Failed</h1>
|
||||
<Box
|
||||
dxDark
|
||||
dxStyle={{ padding: 'var(--default_spacing)', minWidth: '70vw' }}
|
||||
>
|
||||
<h1
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
paddingBottom: 'var(--default_spacing)',
|
||||
color: 'var(--text_color_error)',
|
||||
}}
|
||||
>
|
||||
Mount Failed
|
||||
</h1>
|
||||
{retryList}
|
||||
</Box>
|
||||
</Modal>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let footerItems = [];
|
||||
if (this.props.remoteSupported || this.props.s3Supported) {
|
||||
footerItems.push(<AddMount remoteSupported={this.props.remoteSupported}
|
||||
s3Supported={this.props.s3Supported}
|
||||
key={'hi_' + footerItems.length}/>);
|
||||
footerItems.push(
|
||||
<AddMount
|
||||
remoteSupported={this.props.remoteSupported}
|
||||
s3Supported={this.props.s3Supported}
|
||||
key={'hi_' + footerItems.length}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
footerItems.push(<div key={'hi_' + footerItems.length}
|
||||
style={{height: '27px'}}/>);
|
||||
footerItems.push(
|
||||
<div key={'hi_' + footerItems.length} style={{ height: '27px' }} />
|
||||
);
|
||||
}
|
||||
|
||||
let items = [];
|
||||
for (const provider of this.getProviderList(true)) {
|
||||
items.push((
|
||||
<MountItem allowRemove={false}
|
||||
browseClicked={this.handleBrowseLocation}
|
||||
changed={e => this.handleMountLocationChanged(provider, e.target.value)}
|
||||
clicked={this.handleMountUnMount}
|
||||
key={'it_' + items.length}
|
||||
provider={provider}/>
|
||||
));
|
||||
items.push(<div key={'it_' + items.length}
|
||||
style={{paddingTop: 'var(--default_spacing)'}} />)
|
||||
items.push(
|
||||
<MountItem
|
||||
allowRemove={false}
|
||||
browseClicked={this.handleBrowseLocation}
|
||||
changed={(e) =>
|
||||
this.handleMountLocationChanged(provider, e.target.value)
|
||||
}
|
||||
clicked={this.handleMountUnMount}
|
||||
key={'it_' + items.length}
|
||||
provider={provider}
|
||||
/>
|
||||
);
|
||||
items.push(
|
||||
<div
|
||||
key={'it_' + items.length}
|
||||
style={{ paddingTop: 'var(--default_spacing)' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.remoteSupported) {
|
||||
for (const provider of this.props.RemoteMounts) {
|
||||
items.push((
|
||||
<MountItem allowRemove={true}
|
||||
browseClicked={this.handleBrowseLocation}
|
||||
changed={e => this.handleMountLocationChanged(provider, e.target.value)}
|
||||
clicked={this.handleMountUnMount}
|
||||
key={'it_' + items.length}
|
||||
provider={provider}
|
||||
remote/>
|
||||
));
|
||||
items.push(<div key={'it_' + items.length}
|
||||
style={{paddingTop: 'var(--default_spacing)'}}/>)
|
||||
items.push(
|
||||
<MountItem
|
||||
allowRemove={true}
|
||||
browseClicked={this.handleBrowseLocation}
|
||||
changed={(e) =>
|
||||
this.handleMountLocationChanged(provider, e.target.value)
|
||||
}
|
||||
clicked={this.handleMountUnMount}
|
||||
key={'it_' + items.length}
|
||||
provider={provider}
|
||||
remote
|
||||
/>
|
||||
);
|
||||
items.push(
|
||||
<div
|
||||
key={'it_' + items.length}
|
||||
style={{ paddingTop: 'var(--default_spacing)' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.props.s3Supported) {
|
||||
for (const provider of this.props.S3Mounts) {
|
||||
items.push((
|
||||
<MountItem allowRemove={true}
|
||||
browseClicked={this.handleBrowseLocation}
|
||||
changed={e => this.handleMountLocationChanged(provider, e.target.value)}
|
||||
clicked={this.handleMountUnMount}
|
||||
key={'it_' + items.length}
|
||||
provider={provider}
|
||||
s3/>
|
||||
));
|
||||
items.push(<div key={'it_' + items.length}
|
||||
style={{paddingTop: 'var(--default_spacing)'}}/>)
|
||||
items.push(
|
||||
<MountItem
|
||||
allowRemove={true}
|
||||
browseClicked={this.handleBrowseLocation}
|
||||
changed={(e) =>
|
||||
this.handleMountLocationChanged(provider, e.target.value)
|
||||
}
|
||||
clicked={this.handleMountUnMount}
|
||||
key={'it_' + items.length}
|
||||
provider={provider}
|
||||
s3
|
||||
/>
|
||||
);
|
||||
items.push(
|
||||
<div
|
||||
key={'it_' + items.length}
|
||||
style={{ paddingTop: 'var(--default_spacing)' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
items.splice(items.length - 1, 1);
|
||||
|
||||
return (
|
||||
<div style={{margin: 0, padding: 0}}>
|
||||
<div style={{ margin: 0, padding: 0 }}>
|
||||
{retryDisplay}
|
||||
<div
|
||||
className={this.props.remoteSupported || this.props.s3Supported ? 'MountItemsRemote' : 'MountItems'}>
|
||||
className={
|
||||
this.props.remoteSupported || this.props.s3Supported
|
||||
? 'MountItemsRemote'
|
||||
: 'MountItems'
|
||||
}
|
||||
>
|
||||
{items}
|
||||
</div>
|
||||
<div style={{paddingTop: 'var(--default_spacing)'}}/>
|
||||
<div style={{ paddingTop: 'var(--default_spacing)' }} />
|
||||
{footerItems}
|
||||
</div>);
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
AutoMountProcessed: state.mounts.AutoMountProcessed,
|
||||
InstalledVersion: state.relver.InstalledVersion,
|
||||
@@ -435,20 +584,25 @@ const mapStateToProps = state => {
|
||||
ProviderState: state.mounts.ProviderState,
|
||||
RemoteMounts: state.mounts.RemoteMounts,
|
||||
S3Mounts: state.mounts.S3Mounts,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
|
||||
notifyError: (msg, critical, callback) =>
|
||||
dispatch(notifyError(msg, critical, callback)),
|
||||
resetMountsState: () => dispatch(resetMountsState()),
|
||||
setAllowMount: (provider, allow) => dispatch(setAllowMount(provider, allow)),
|
||||
setAutoMountProcessed: (provider, processed) => dispatch(setAutoMountProcessed(provider, processed)),
|
||||
setAllowMount: (provider, allow) =>
|
||||
dispatch(setAllowMount(provider, allow)),
|
||||
setAutoMountProcessed: (provider, processed) =>
|
||||
dispatch(setAutoMountProcessed(provider, processed)),
|
||||
setMounted: (provider, mounted) => dispatch(setMounted(provider, mounted)),
|
||||
setMountsBusy: busy => dispatch(setBusy(busy)),
|
||||
setMountState: (provider, state) => dispatch(setMountState(provider, state)),
|
||||
setProviderState: (provider, state) => dispatch(setProviderState(provider, state)),
|
||||
}
|
||||
setMountsBusy: (busy) => dispatch(setBusy(busy)),
|
||||
setMountState: (provider, state) =>
|
||||
dispatch(setMountState(provider, state)),
|
||||
setProviderState: (provider, state) =>
|
||||
dispatch(setProviderState(provider, state)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(MountItems);
|
||||
|
||||
@@ -1,180 +1,227 @@
|
||||
import React from 'react';
|
||||
import './PinnedManager.css';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||
import {notifyApplicationBusy} from '../../redux/actions/common_actions';
|
||||
import {notifyError, notifyInfo} from '../../redux/actions/error_actions';
|
||||
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
|
||||
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 {faFolder} from '@fortawesome/free-solid-svg-icons';
|
||||
import { displayPinnedManager } from '../../redux/actions/pinned_manager_actions';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
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 => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
DisplayConfiguration: state.mounts.DisplayConfiguration,
|
||||
DisplayRemoteConfiguration: state.mounts.DisplayRemoteConfiguration,
|
||||
DisplayS3Configuration: state.mounts.DisplayS3Configuration,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
displayPinnedManager: display => dispatch(displayPinnedManager(display)),
|
||||
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
|
||||
displayPinnedManager: (display) => dispatch(displayPinnedManager(display)),
|
||||
notifyApplicationBusy: (busy) =>
|
||||
dispatch(notifyApplicationBusy(busy, true)),
|
||||
notifyError: (msg, cb) => dispatch(notifyError(msg, false, cb)),
|
||||
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg)),
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCContainer {
|
||||
state = {
|
||||
active_directory: '/',
|
||||
items: [],
|
||||
previous: [],
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
class extends IPCContainer {
|
||||
state = {
|
||||
active_directory: '/',
|
||||
items: [],
|
||||
previous: [],
|
||||
};
|
||||
|
||||
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, () => {
|
||||
this.props.displayPinnedManager(false);
|
||||
});
|
||||
componentDidMount() {
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Get_Directory_Items_Reply,
|
||||
this.onGetDirectoryItemsReply
|
||||
);
|
||||
this.grabDirectoryItems();
|
||||
}
|
||||
}
|
||||
|
||||
createDirectory = (name, path, idx, total, item_idx) => {
|
||||
const style = {}
|
||||
if (item_idx + 1 !== total) {
|
||||
style.marginBottom = '4px';
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
}
|
||||
return (
|
||||
<div key={'dir_' + idx} style={{...style}}>
|
||||
<Button buttonStyles={{textAlign: 'left'}}
|
||||
clicked={() => {
|
||||
const previous = [...this.state.previous];
|
||||
if (path === '..') {
|
||||
path = previous.pop();
|
||||
} else {
|
||||
previous.push(this.state.active_directory);
|
||||
}
|
||||
this.setState({
|
||||
items: [],
|
||||
active_directory: path,
|
||||
previous,
|
||||
}, () => {
|
||||
this.grabDirectoryItems();
|
||||
});
|
||||
}}>
|
||||
<FontAwesomeIcon icon={faFolder}
|
||||
fixedWidth
|
||||
color={'var(--heading_text_color)'}
|
||||
style={{padding: 0, margin: 0}}/>
|
||||
{name}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
createFile = (name, path, pinned, idx, total, item_idx) => {
|
||||
const style = {textAlign: 'left'}
|
||||
if (item_idx + 1 !== total) {
|
||||
style.marginBottom = '2px';
|
||||
}
|
||||
return (
|
||||
<div key={'file_' + idx} style={{...style}}>
|
||||
<CheckBox checked={pinned}
|
||||
changed={() => {
|
||||
const items = JSON.parse(JSON.stringify(this.state.items));
|
||||
const pinned = 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: path,
|
||||
Pinned: pinned,
|
||||
});
|
||||
});
|
||||
}}
|
||||
label={name}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
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,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let idx = 0;
|
||||
return (
|
||||
<Box dxDark dxStyle={{
|
||||
height: 'calc(100vh - (var(--default_spacing) * 4)',
|
||||
padding: 'var(--default_spacing)',
|
||||
width: 'calc(100vw - (var(--default_spacing) * 4)'
|
||||
}}>
|
||||
<div className={'PinnedManager'}>
|
||||
<div className={'PinnedManagerHeading'}>
|
||||
<div className={'PinnedManagerClose'}>
|
||||
<a href={'#'}
|
||||
onClick={() => this.props.displayPinnedManager(false)}
|
||||
style={{cursor: 'pointer', flex: '0'}}>X</a>
|
||||
</div>
|
||||
<h1 style={{width: '100%', textAlign: 'center'}}>{'Pinned File Manager'}</h1>
|
||||
<div className={'PinnedManagerActiveDirectory'}>
|
||||
<b> {this.state.active_directory}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'PinnedManagerItemsOwner'}>
|
||||
<div className={'PinnedManagerItems'}>
|
||||
{
|
||||
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.path, i.meta.pinned, idx++, this.state.items.length, k);
|
||||
})
|
||||
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, () => {
|
||||
this.props.displayPinnedManager(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
createDirectory = (name, path, idx, total, item_idx) => {
|
||||
const style = {};
|
||||
if (item_idx + 1 !== total) {
|
||||
style.marginBottom = '4px';
|
||||
}
|
||||
return (
|
||||
<div key={'dir_' + idx} style={{ ...style }}>
|
||||
<Button
|
||||
buttonStyles={{ textAlign: 'left' }}
|
||||
clicked={() => {
|
||||
const previous = [...this.state.previous];
|
||||
if (path === '..') {
|
||||
path = previous.pop();
|
||||
} else {
|
||||
previous.push(this.state.active_directory);
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
items: [],
|
||||
active_directory: path,
|
||||
previous,
|
||||
},
|
||||
() => {
|
||||
this.grabDirectoryItems();
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faFolder}
|
||||
fixedWidth
|
||||
color={'var(--heading_text_color)'}
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
{name}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
createFile = (name, path, pinned, idx, total, item_idx) => {
|
||||
const style = { textAlign: 'left' };
|
||||
if (item_idx + 1 !== total) {
|
||||
style.marginBottom = '2px';
|
||||
}
|
||||
return (
|
||||
<div key={'file_' + idx} style={{ ...style }}>
|
||||
<CheckBox
|
||||
checked={pinned}
|
||||
changed={() => {
|
||||
const items = JSON.parse(JSON.stringify(this.state.items));
|
||||
const pinned = (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: path,
|
||||
Pinned: pinned,
|
||||
});
|
||||
}
|
||||
);
|
||||
}}
|
||||
label={name}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
let idx = 0;
|
||||
return (
|
||||
<Box
|
||||
dxDark
|
||||
dxStyle={{
|
||||
height: 'calc(100vh - (var(--default_spacing) * 4)',
|
||||
padding: 'var(--default_spacing)',
|
||||
width: 'calc(100vw - (var(--default_spacing) * 4)',
|
||||
}}
|
||||
>
|
||||
<div className={'PinnedManager'}>
|
||||
<div className={'PinnedManagerHeading'}>
|
||||
<div className={'PinnedManagerClose'}>
|
||||
<a
|
||||
href={'#'}
|
||||
onClick={() => this.props.displayPinnedManager(false)}
|
||||
style={{ cursor: 'pointer', flex: '0' }}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<h1 style={{ width: '100%', textAlign: 'center' }}>
|
||||
{'Pinned File Manager'}
|
||||
</h1>
|
||||
<div className={'PinnedManagerActiveDirectory'}>
|
||||
<b> {this.state.active_directory}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'PinnedManagerItemsOwner'}>
|
||||
<div className={'PinnedManagerItems'}>
|
||||
{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.path,
|
||||
i.meta.pinned,
|
||||
idx++,
|
||||
this.state.items.length,
|
||||
k
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
)
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,43 +1,50 @@
|
||||
import React from 'react';
|
||||
import './SelectAppPlatform.css';
|
||||
import axios from 'axios';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Constants from '../../constants';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import {
|
||||
downloadItem,
|
||||
setAllowDownload
|
||||
setAllowDownload,
|
||||
} from '../../redux/actions/download_actions';
|
||||
import DropDown from '../../components/UI/DropDown/DropDown';
|
||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||
import {notifyError} from '../../redux/actions/error_actions';
|
||||
import {setInstallTestActive} from '../../redux/actions/install_actions';
|
||||
import { notifyError } from '../../redux/actions/error_actions';
|
||||
import { setInstallTestActive } from '../../redux/actions/install_actions';
|
||||
|
||||
class SelectAppPlatform extends IPCContainer {
|
||||
state = {
|
||||
Selected: 0,
|
||||
};
|
||||
|
||||
grabLatestRelease = appPlatform => {
|
||||
const errorHandler = error => {
|
||||
grabLatestRelease = (appPlatform) => {
|
||||
const errorHandler = (error) => {
|
||||
this.props.notifyError(error);
|
||||
this.props.setInstallTestActive(false);
|
||||
this.props.setAllowDownload(false);
|
||||
};
|
||||
axios
|
||||
.get(Constants.RELEASES_URL)
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
try {
|
||||
const releases = response.data.Versions.Release[appPlatform];
|
||||
const latestVersion = releases[releases.length - 1];
|
||||
const release = response.data.Locations[appPlatform][latestVersion];
|
||||
this.props.downloadItem(latestVersion + '.zip', Constants.INSTALL_TYPES.TestRelease, release.urls, false, latestVersion, appPlatform);
|
||||
this.props.downloadItem(
|
||||
latestVersion + '.zip',
|
||||
Constants.INSTALL_TYPES.TestRelease,
|
||||
release.urls,
|
||||
false,
|
||||
latestVersion,
|
||||
appPlatform
|
||||
);
|
||||
} catch (error) {
|
||||
errorHandler(error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
errorHandler(error);
|
||||
});
|
||||
};
|
||||
@@ -45,10 +52,12 @@ class SelectAppPlatform extends IPCContainer {
|
||||
handleTestClicked = () => {
|
||||
this.props.setInstallTestActive(true);
|
||||
this.props.setAllowDownload(true);
|
||||
this.grabLatestRelease(Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected])
|
||||
this.grabLatestRelease(
|
||||
Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]
|
||||
);
|
||||
};
|
||||
|
||||
handleChanged = e => {
|
||||
handleChanged = (e) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
Selected: Constants.LINUX_SELECTABLE_PLATFORMS.indexOf(e.target.value),
|
||||
@@ -57,36 +66,48 @@ class SelectAppPlatform extends IPCContainer {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<h1 className={'SAPHeading'}>Select Linux Platform</h1>
|
||||
<div className={'SAPContent'}>
|
||||
<p>Repertory was unable to detect your Linux distribution. Please select one of the following and click <b>Test</b> to continue:</p>
|
||||
<p>
|
||||
Repertory was unable to detect your Linux distribution. Please
|
||||
select one of the following and click <b>Test</b> to continue:
|
||||
</p>
|
||||
</div>
|
||||
<div className={'SAPActions'}>
|
||||
<DropDown changed={this.handleChanged}
|
||||
disabled={this.props.InstallTestActive}
|
||||
items={Constants.LINUX_SELECTABLE_PLATFORMS}
|
||||
selected={Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]}/>
|
||||
<Button clicked={this.handleTestClicked}
|
||||
disabled={this.props.InstallTestActive}>Test</Button>
|
||||
<DropDown
|
||||
changed={this.handleChanged}
|
||||
disabled={this.props.InstallTestActive}
|
||||
items={Constants.LINUX_SELECTABLE_PLATFORMS}
|
||||
selected={Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]}
|
||||
/>
|
||||
<Button
|
||||
clicked={this.handleTestClicked}
|
||||
disabled={this.props.InstallTestActive}
|
||||
>
|
||||
Test
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
InstallTestActive: state.install.InstallTestActive,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
downloadItem: (name, type, urls, isWinFSP, testVersion, appPlatform) => dispatch(downloadItem(name, type, urls, isWinFSP, testVersion, appPlatform)),
|
||||
notifyError: msg => dispatch(notifyError(msg)),
|
||||
setAllowDownload: allow => dispatch(setAllowDownload(allow)),
|
||||
setInstallTestActive: active => dispatch(setInstallTestActive(active)),
|
||||
downloadItem: (name, type, urls, isWinFSP, testVersion, appPlatform) =>
|
||||
dispatch(
|
||||
downloadItem(name, type, urls, isWinFSP, testVersion, appPlatform)
|
||||
),
|
||||
notifyError: (msg) => dispatch(notifyError(msg)),
|
||||
setAllowDownload: (allow) => dispatch(setAllowDownload(allow)),
|
||||
setInstallTestActive: (active) => dispatch(setInstallTestActive(active)),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,59 +1,78 @@
|
||||
import React from 'react';
|
||||
import './SkynetExport.css';
|
||||
import CheckboxTree from 'react-checkbox-tree';
|
||||
import {connect} from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||
import {notifyApplicationBusy} from '../../redux/actions/common_actions';
|
||||
import {notifyError, notifyInfo} from '../../redux/actions/error_actions';
|
||||
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
|
||||
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import {displaySkynetExport} from '../../redux/actions/skynet_actions';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import { displaySkynetExport } from '../../redux/actions/skynet_actions';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faCheckSquare, faChevronDown,
|
||||
faChevronRight, faFile, faFolder, faFolderOpen,
|
||||
faHSquare, faMinusSquare, faPlusSquare,
|
||||
faSquare
|
||||
faCheckSquare,
|
||||
faChevronDown,
|
||||
faChevronRight,
|
||||
faFile,
|
||||
faFolder,
|
||||
faFolderOpen,
|
||||
faHSquare,
|
||||
faMinusSquare,
|
||||
faPlusSquare,
|
||||
faSquare,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
|
||||
const Constants = require('../../constants');
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
AppBusy: state.common.AppBusy,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
displaySkynetExport: display => dispatch(displaySkynetExport(display)),
|
||||
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
|
||||
notifyError: msg => dispatch(notifyError(msg)),
|
||||
displaySkynetExport: (display) => dispatch(displaySkynetExport(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 extends IPCContainer {
|
||||
state = {
|
||||
checked: [],
|
||||
clicked: {},
|
||||
expanded: [],
|
||||
nodes: [],
|
||||
second_stage: false,
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
class extends IPCContainer {
|
||||
state = {
|
||||
checked: [],
|
||||
clicked: {},
|
||||
expanded: [],
|
||||
nodes: [],
|
||||
second_stage: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setRequestHandler(Constants.IPC_Grab_Skynet_Tree_Reply, this.onGrabSkynetTreeReply);
|
||||
this.setRequestHandler(Constants.IPC_Export_Skylinks_Reply, this.onExportSkylinksReply);
|
||||
this.sendRequest(Constants.IPC_Grab_Skynet_Tree, {Version: this.props.version});
|
||||
}
|
||||
componentDidMount() {
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Grab_Skynet_Tree_Reply,
|
||||
this.onGrabSkynetTreeReply
|
||||
);
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Export_Skylinks_Reply,
|
||||
this.onExportSkylinksReply
|
||||
);
|
||||
this.sendRequest(Constants.IPC_Grab_Skynet_Tree, {
|
||||
Version: this.props.version,
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
}
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
}
|
||||
|
||||
createNodes = items => {
|
||||
/*
|
||||
createNodes = (items) => {
|
||||
/*
|
||||
{
|
||||
name: '',
|
||||
path: '',
|
||||
@@ -61,175 +80,269 @@ export default connect(mapStateToProps, mapDispatchToProps)(class extends IPCCon
|
||||
children: [],
|
||||
}
|
||||
*/
|
||||
const ret = [];
|
||||
for (const item of items) {
|
||||
const treeItem = {
|
||||
label: item.name,
|
||||
path: item.path,
|
||||
value: item.name === '/' ? 0 : item.path ? item.path : JSON.stringify(item),
|
||||
};
|
||||
const ret = [];
|
||||
for (const item of items) {
|
||||
const treeItem = {
|
||||
label: item.name,
|
||||
path: item.path,
|
||||
value:
|
||||
item.name === '/'
|
||||
? 0
|
||||
: item.path
|
||||
? item.path
|
||||
: JSON.stringify(item),
|
||||
};
|
||||
|
||||
if (item.directory) {
|
||||
treeItem.children = this.createNodes(item.children);
|
||||
if (item.directory) {
|
||||
treeItem.children = this.createNodes(item.children);
|
||||
}
|
||||
|
||||
ret.push(treeItem);
|
||||
}
|
||||
|
||||
ret.push(treeItem);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
handleNavigation = () => {
|
||||
if (this.state.second_stage) {
|
||||
this.props.notifyApplicationBusy(true);
|
||||
this.sendRequest(Constants.IPC_Export_Skylinks, {
|
||||
Version: this.props.version,
|
||||
Paths: this.state.checked,
|
||||
});
|
||||
} else {
|
||||
if (this.state.checked.length === 0) {
|
||||
this.props.notifyError('No files have been checked');
|
||||
} else {
|
||||
this.setState({
|
||||
second_stage: true,
|
||||
handleNavigation = () => {
|
||||
if (this.state.second_stage) {
|
||||
this.props.notifyApplicationBusy(true);
|
||||
this.sendRequest(Constants.IPC_Export_Skylinks, {
|
||||
Version: this.props.version,
|
||||
Paths: this.state.checked,
|
||||
});
|
||||
} else {
|
||||
if (this.state.checked.length === 0) {
|
||||
this.props.notifyError('No files have been checked');
|
||||
} else {
|
||||
this.setState({
|
||||
second_stage: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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) => {
|
||||
if (arg.data.Success) {
|
||||
this.setState({
|
||||
checked: [],
|
||||
expanded: [0],
|
||||
nodes: this.createNodes(arg.data.Result),
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
checked: [],
|
||||
expanded: [],
|
||||
nodes: [],
|
||||
}, () => {
|
||||
this.props.notifyError(arg.data.Error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.AppBusy ? (<div/>) : (
|
||||
<Box dxDark dxStyle={{
|
||||
height: '90vh',
|
||||
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.displaySkynetExport(false)}
|
||||
style={{cursor: 'pointer'}}>X</a>
|
||||
</div>
|
||||
<h1
|
||||
className={'SkynetExportHeading'}>{this.state.second_stage ? 'Verify Exports' : 'Export Files'}</h1>
|
||||
<div className={this.state.second_stage ? 'SkynetExportList' : 'SkynetExportTree'}>
|
||||
onExportSkylinksReply = (_, arg) => {
|
||||
this.props.notifyApplicationBusy(false);
|
||||
if (arg.data.Success) {
|
||||
this.setState(
|
||||
{
|
||||
this.state.second_stage ?
|
||||
this.state.checked.map(path => {
|
||||
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) => {
|
||||
if (arg.data.Success) {
|
||||
this.setState({
|
||||
checked: [],
|
||||
expanded: [0],
|
||||
nodes: this.createNodes(arg.data.Result),
|
||||
});
|
||||
} else {
|
||||
this.setState(
|
||||
{
|
||||
checked: [],
|
||||
expanded: [],
|
||||
nodes: [],
|
||||
},
|
||||
() => {
|
||||
this.props.notifyError(arg.data.Error);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return this.props.AppBusy ? (
|
||||
<div />
|
||||
) : (
|
||||
<Box
|
||||
dxDark
|
||||
dxStyle={{
|
||||
height: '90vh',
|
||||
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.displaySkynetExport(false)}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<h1 className={'SkynetExportHeading'}>
|
||||
{this.state.second_stage ? 'Verify Exports' : 'Export Files'}
|
||||
</h1>
|
||||
<div
|
||||
className={
|
||||
this.state.second_stage ? 'SkynetExportList' : 'SkynetExportTree'
|
||||
}
|
||||
>
|
||||
{this.state.second_stage ? (
|
||||
this.state.checked.map((path) => {
|
||||
return (
|
||||
<input readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
key={path}
|
||||
style={{width: '100%', marginBottom: 'var(--default_spacing)'}}
|
||||
type={'text'}
|
||||
value={path}/>
|
||||
<input
|
||||
readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
key={path}
|
||||
style={{
|
||||
width: '100%',
|
||||
marginBottom: 'var(--default_spacing)',
|
||||
}}
|
||||
type={'text'}
|
||||
value={path}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: (
|
||||
<CheckboxTree checked={this.state.checked}
|
||||
expanded={this.state.expanded}
|
||||
expandOnClick
|
||||
showExpandAll
|
||||
icons={{
|
||||
check: <FontAwesomeIcon icon={faCheckSquare} fixedWidth
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
uncheck: <FontAwesomeIcon icon={faSquare} fixedWidth
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
halfCheck: <FontAwesomeIcon icon={faHSquare} fixedWidth
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
expandClose: <FontAwesomeIcon icon={faChevronRight} fixedWidth
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
expandOpen: <FontAwesomeIcon icon={faChevronDown} fixedWidth
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
expandAll: <FontAwesomeIcon icon={faPlusSquare} fixedWidth
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
collapseAll: <FontAwesomeIcon icon={faMinusSquare} fixedWidth
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
parentClose: <FontAwesomeIcon icon={faFolder}
|
||||
fixedWidth
|
||||
color={'var(--heading_text_color)'}
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
parentOpen: <FontAwesomeIcon icon={faFolderOpen}
|
||||
fixedWidth
|
||||
color={'var(--heading_text_color)'}
|
||||
style={{padding: 0, margin: 0}}/>,
|
||||
leaf: <FontAwesomeIcon icon={faFile}
|
||||
fixedWidth
|
||||
color={'var(--text_color)'}
|
||||
style={{padding: 0, margin: 0}}/>
|
||||
}}
|
||||
nodes={this.state.nodes}
|
||||
onClick={clicked => this.setState({clicked})}
|
||||
onCheck={checked => this.setState({checked})}
|
||||
onExpand={expanded => this.setState({expanded})}/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div style={{display: 'flex', justifyContent: 'flex-end'}}>
|
||||
{
|
||||
this.state.second_stage ?
|
||||
<Button buttonStyles={{
|
||||
) : (
|
||||
<CheckboxTree
|
||||
checked={this.state.checked}
|
||||
expanded={this.state.expanded}
|
||||
expandOnClick
|
||||
showExpandAll
|
||||
icons={{
|
||||
check: (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheckSquare}
|
||||
fixedWidth
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
uncheck: (
|
||||
<FontAwesomeIcon
|
||||
icon={faSquare}
|
||||
fixedWidth
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
halfCheck: (
|
||||
<FontAwesomeIcon
|
||||
icon={faHSquare}
|
||||
fixedWidth
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
expandClose: (
|
||||
<FontAwesomeIcon
|
||||
icon={faChevronRight}
|
||||
fixedWidth
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
expandOpen: (
|
||||
<FontAwesomeIcon
|
||||
icon={faChevronDown}
|
||||
fixedWidth
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
expandAll: (
|
||||
<FontAwesomeIcon
|
||||
icon={faPlusSquare}
|
||||
fixedWidth
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
collapseAll: (
|
||||
<FontAwesomeIcon
|
||||
icon={faMinusSquare}
|
||||
fixedWidth
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
parentClose: (
|
||||
<FontAwesomeIcon
|
||||
icon={faFolder}
|
||||
fixedWidth
|
||||
color={'var(--heading_text_color)'}
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
parentOpen: (
|
||||
<FontAwesomeIcon
|
||||
icon={faFolderOpen}
|
||||
fixedWidth
|
||||
color={'var(--heading_text_color)'}
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
leaf: (
|
||||
<FontAwesomeIcon
|
||||
icon={faFile}
|
||||
fixedWidth
|
||||
color={'var(--text_color)'}
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
nodes={this.state.nodes}
|
||||
onClick={(clicked) => this.setState({ clicked })}
|
||||
onCheck={(checked) => this.setState({ checked })}
|
||||
onExpand={(expanded) => this.setState({ expanded })}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
{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}
|
||||
<Button
|
||||
buttonStyles={{
|
||||
height: 'auto',
|
||||
marginLeft: 'var(--default_spacing)',
|
||||
marginTop: 'var(--default_spacing)',
|
||||
width: 'auto'
|
||||
}} clicked={() => this.setState({
|
||||
second_stage: false,
|
||||
})}>{'Back'}</Button> :
|
||||
null
|
||||
}
|
||||
<Button buttonStyles={{
|
||||
height: 'auto',
|
||||
marginLeft: 'var(--default_spacing)',
|
||||
marginTop: 'var(--default_spacing)',
|
||||
width: 'auto'
|
||||
}}
|
||||
clicked={this.handleNavigation}>{this.state.second_stage ? 'Export' : 'Next'}</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
width: 'auto',
|
||||
}}
|
||||
clicked={this.handleNavigation}
|
||||
>
|
||||
{this.state.second_stage ? 'Export' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,30 +1,36 @@
|
||||
import React from 'react'
|
||||
import './Import.css'
|
||||
import React from 'react';
|
||||
import './Import.css';
|
||||
|
||||
const Import = ({data}) => {
|
||||
const Import = ({ data }) => {
|
||||
return (
|
||||
<div className={'ImportOwner'}>
|
||||
<input readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{
|
||||
maxWidth: 'calc(33.33% - var(--default_spacing)',
|
||||
marginRight: 'var(--default_spacing)'
|
||||
}}
|
||||
type={'text'}
|
||||
value={data.directory}/>
|
||||
<input readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))'}}
|
||||
type={'text'}
|
||||
value={data.skylink}/>
|
||||
<input readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{
|
||||
maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))',
|
||||
marginLeft: 'var(--default_spacing)'
|
||||
}}
|
||||
type={'text'}
|
||||
value={data.token}/>
|
||||
<input
|
||||
readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{
|
||||
maxWidth: 'calc(33.33% - var(--default_spacing)',
|
||||
marginRight: 'var(--default_spacing)',
|
||||
}}
|
||||
type={'text'}
|
||||
value={data.directory}
|
||||
/>
|
||||
<input
|
||||
readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))' }}
|
||||
type={'text'}
|
||||
value={data.skylink}
|
||||
/>
|
||||
<input
|
||||
readOnly
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{
|
||||
maxWidth: 'calc(33.33% - calc(var(--default_spacing) / 2))',
|
||||
marginLeft: 'var(--default_spacing)',
|
||||
}}
|
||||
type={'text'}
|
||||
value={data.token}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,29 +1,38 @@
|
||||
import React from 'react'
|
||||
import './ImportList.css'
|
||||
import Import from './Import/Import'
|
||||
import React from 'react';
|
||||
import './ImportList.css';
|
||||
import Import from './Import/Import';
|
||||
import Text from '../../../components/UI/Text/Text';
|
||||
|
||||
const ImportList = ({imports_array}) => {
|
||||
const ImportList = ({ imports_array }) => {
|
||||
let key = 0;
|
||||
return (
|
||||
<div>
|
||||
<div className={'ImportListHeader'}>
|
||||
<Text type={'Heading1'} text={'Directory'}
|
||||
style={{minWidth: '33.33%', maxWidth: '33.33%'}}/>
|
||||
<Text type={'Heading1'} text={'Skylink'} style={{minWidth: '33.33%', maxWidth: '33.33%'}}/>
|
||||
<Text type={'Heading1'} text={'Token'} style={{minWidth: '33.33%', maxWidth: '33.33%'}}/>
|
||||
<Text
|
||||
type={'Heading1'}
|
||||
text={'Directory'}
|
||||
style={{ minWidth: '33.33%', maxWidth: '33.33%' }}
|
||||
/>
|
||||
<Text
|
||||
type={'Heading1'}
|
||||
text={'Skylink'}
|
||||
style={{ minWidth: '33.33%', maxWidth: '33.33%' }}
|
||||
/>
|
||||
<Text
|
||||
type={'Heading1'}
|
||||
text={'Token'}
|
||||
style={{ minWidth: '33.33%', maxWidth: '33.33%' }}
|
||||
/>
|
||||
</div>
|
||||
<hr/>
|
||||
<hr />
|
||||
<div className={'ImportListOwner'}>
|
||||
{
|
||||
imports_array.map(data => {
|
||||
return (
|
||||
<div key={'import_' + key++}>
|
||||
<Import data={data}/>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
{imports_array.map((data) => {
|
||||
return (
|
||||
<div key={'import_' + key++}>
|
||||
<Import data={data} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,228 +1,278 @@
|
||||
import React from 'react'
|
||||
import {connect} from 'react-redux';
|
||||
import './SkynetImport.css'
|
||||
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 { 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 { notifyApplicationBusy } from '../../redux/actions/common_actions';
|
||||
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
|
||||
|
||||
const Constants = require('../../constants');
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
AppBusy: state.common.AppBusy,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
displaySkynetImport: display => dispatch(displaySkynetImport(display)),
|
||||
notifyApplicationBusy: busy => dispatch(notifyApplicationBusy(busy, true)),
|
||||
notifyError: msg => dispatch(notifyError(msg)),
|
||||
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 {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
class SkynetImport extends IPCContainer {
|
||||
state = {
|
||||
import_text: '',
|
||||
imports_array: [],
|
||||
second_stage: false,
|
||||
};
|
||||
|
||||
state = {
|
||||
import_text: '',
|
||||
imports_array: [],
|
||||
second_stage: false,
|
||||
};
|
||||
componentDidMount() {
|
||||
this.setRequestHandler(
|
||||
Constants.IPC_Import_Skylinks_Reply,
|
||||
this.onImportSkylinksReply
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setRequestHandler(Constants.IPC_Import_Skylinks_Reply, this.onImportSkylinksReply);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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, ''),
|
||||
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 (!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');
|
||||
if (importsArray.length === 0) {
|
||||
throw new Error('Nothing to import');
|
||||
}
|
||||
this.setState({
|
||||
imports_array: importsArray,
|
||||
second_stage: true,
|
||||
});
|
||||
} catch (e) {
|
||||
this.props.notifyError(e);
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
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}/>
|
||||
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={{
|
||||
<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}
|
||||
<Button
|
||||
buttonStyles={{
|
||||
height: 'auto',
|
||||
marginLeft: 'var(--default_spacing)',
|
||||
marginTop: 'var(--default_spacing)',
|
||||
width: 'auto'
|
||||
}} clicked={() => this.setState({
|
||||
second_stage: false,
|
||||
})}>{'Back'}</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>
|
||||
width: 'auto',
|
||||
}}
|
||||
clicked={this.handleNavigation}
|
||||
>
|
||||
{this.state.second_stage ? 'Import' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {Component} from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import './Password.css';
|
||||
import {faEye, faEyeSlash} from '@fortawesome/free-solid-svg-icons';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
export default class Password extends Component {
|
||||
state = {
|
||||
@@ -12,14 +12,14 @@ export default class Password extends Component {
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.value || (this.props.value.length === 0)) {
|
||||
if (!this.props.value || this.props.value.length === 0) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
button_text: 'set',
|
||||
password: '',
|
||||
password2: '',
|
||||
show_password: false,
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
...this.state,
|
||||
@@ -27,7 +27,7 @@ export default class Password extends Component {
|
||||
password: this.props.value,
|
||||
password2: '',
|
||||
show_password: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,20 +48,26 @@ export default class Password extends Component {
|
||||
this.props.changed(this.state.password);
|
||||
this.setState({
|
||||
...this.state,
|
||||
button_text: this.state.password && this.state.password.length > 0 ? 'clear' : 'set',
|
||||
button_text:
|
||||
this.state.password && this.state.password.length > 0
|
||||
? 'clear'
|
||||
: 'set',
|
||||
password2: '',
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
...this.state,
|
||||
button_text: 'set',
|
||||
password: '',
|
||||
password2: '',
|
||||
}, () => {
|
||||
if (this.props.mismatchHandler) {
|
||||
this.props.mismatchHandler();
|
||||
this.setState(
|
||||
{
|
||||
...this.state,
|
||||
button_text: 'set',
|
||||
password: '',
|
||||
password2: '',
|
||||
},
|
||||
() => {
|
||||
if (this.props.mismatchHandler) {
|
||||
this.props.mismatchHandler();
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -79,7 +85,7 @@ export default class Password extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
handlePasswordChanged = e => {
|
||||
handlePasswordChanged = (e) => {
|
||||
if (this.state.button_text === 'set') {
|
||||
this.setState({
|
||||
...this.state,
|
||||
@@ -93,8 +99,11 @@ export default class Password extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
handlePasswordKeyUp = e => {
|
||||
if ((e.keyCode === 13) && ((this.state.button_text === 'confirm') || (this.state.button_text === 'set'))) {
|
||||
handlePasswordKeyUp = (e) => {
|
||||
if (
|
||||
e.keyCode === 13 &&
|
||||
(this.state.button_text === 'confirm' || this.state.button_text === 'set')
|
||||
) {
|
||||
this.handleActionClick();
|
||||
}
|
||||
};
|
||||
@@ -108,28 +117,41 @@ export default class Password extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={'PasswordOwner'} style={{...this.props.style}}>
|
||||
{
|
||||
this.props.readOnly ? null : <a href={'#'}
|
||||
className={'PasswordLink'}
|
||||
onClick={this.handleActionClick}>
|
||||
<div className={'PasswordOwner'} style={{ ...this.props.style }}>
|
||||
{this.props.readOnly ? null : (
|
||||
<a
|
||||
href={'#'}
|
||||
className={'PasswordLink'}
|
||||
onClick={this.handleActionClick}
|
||||
>
|
||||
<u>{this.state.button_text}</u>
|
||||
</a>
|
||||
}
|
||||
<input autoFocus={this.props.autoFocus}
|
||||
readOnly={this.props.readOnly}
|
||||
className={'PasswordInput'}
|
||||
disabled={this.props.readOnly || (this.state.button_text === 'clear')}
|
||||
onChange={this.handlePasswordChanged}
|
||||
onKeyUp={this.handlePasswordKeyUp}
|
||||
type={this.state.show_password ? 'text' : 'password'}
|
||||
value={(this.state.button_text === 'confirm') ? this.state.password2 : this.state.password}/>
|
||||
<a href={'#'}
|
||||
className={'PasswordShowHide'}
|
||||
onClick={this.handleShowHideClick}>
|
||||
<FontAwesomeIcon icon={this.state.show_password ? faEye : faEyeSlash} fixedWidth/>
|
||||
)}
|
||||
<input
|
||||
autoFocus={this.props.autoFocus}
|
||||
readOnly={this.props.readOnly}
|
||||
className={'PasswordInput'}
|
||||
disabled={this.props.readOnly || this.state.button_text === 'clear'}
|
||||
onChange={this.handlePasswordChanged}
|
||||
onKeyUp={this.handlePasswordKeyUp}
|
||||
type={this.state.show_password ? 'text' : 'password'}
|
||||
value={
|
||||
this.state.button_text === 'confirm'
|
||||
? this.state.password2
|
||||
: this.state.password
|
||||
}
|
||||
/>
|
||||
<a
|
||||
href={'#'}
|
||||
className={'PasswordShowHide'}
|
||||
onClick={this.handleShowHideClick}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={this.state.show_password ? faEye : faEyeSlash}
|
||||
fixedWidth
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
1082
src/helpers.js
1082
src/helpers.js
File diff suppressed because it is too large
Load Diff
@@ -8,28 +8,33 @@ test('verify signature success', () => {
|
||||
.verifySignature(
|
||||
path.resolve('test/test_verify_signature.dat'),
|
||||
path.resolve('test/test_verify_signature.dat.sig'),
|
||||
path.resolve('blockstorage_dev_public.pem'))
|
||||
.then(stdout => {
|
||||
path.resolve('blockstorage_dev_public.pem')
|
||||
)
|
||||
.then((stdout) => {
|
||||
expect(stdout).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test('verify signature fail', () => {
|
||||
return expect(helpers
|
||||
.verifySignature(
|
||||
return expect(
|
||||
helpers.verifySignature(
|
||||
path.resolve('test/test_verify_signature_fail.dat'),
|
||||
path.resolve('test/test_verify_signature.dat.sig'),
|
||||
path.resolve('blockstorage_dev_public.pem')))
|
||||
.rejects
|
||||
.toThrow()
|
||||
path.resolve('blockstorage_dev_public.pem')
|
||||
)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('create temp signature files', () => {
|
||||
const b64signature = fs.readFileSync(path.resolve('test/test_create_signature.sig.b64'), {encoding: 'utf8'}).replace(/(\r\n|\n|\r)/gm,"");
|
||||
const data = helpers
|
||||
.createSignatureFiles(
|
||||
b64signature,
|
||||
Constants.DEV_PUBLIC_KEY);
|
||||
const b64signature = fs
|
||||
.readFileSync(path.resolve('test/test_create_signature.sig.b64'), {
|
||||
encoding: 'utf8',
|
||||
})
|
||||
.replace(/(\r\n|\n|\r)/gm, '');
|
||||
const data = helpers.createSignatureFiles(
|
||||
b64signature,
|
||||
Constants.DEV_PUBLIC_KEY
|
||||
);
|
||||
expect(data).toBeDefined();
|
||||
expect(data.PublicKeyFile).toBeDefined();
|
||||
expect(data.SignatureFile).toBeDefined();
|
||||
@@ -37,22 +42,33 @@ test('create temp signature files', () => {
|
||||
expect(fs.statSync(data.SignatureFile).isFile()).toBe(true);
|
||||
expect(fs.statSync(data.PublicKeyFile).isFile()).toBe(true);
|
||||
|
||||
const b64signature2 = fs.readFileSync(data.SignatureFile).toString('base64').replace(/(\r\n|\n|\r)/gm,"");
|
||||
const b64signature2 = fs
|
||||
.readFileSync(data.SignatureFile)
|
||||
.toString('base64')
|
||||
.replace(/(\r\n|\n|\r)/gm, '');
|
||||
expect(b64signature2).toEqual(b64signature);
|
||||
|
||||
expect(fs.readFileSync(data.PublicKeyFile, {encoding: 'utf8'})).toEqual(Constants.DEV_PUBLIC_KEY);
|
||||
expect(fs.readFileSync(data.PublicKeyFile, { encoding: 'utf8' })).toEqual(
|
||||
Constants.DEV_PUBLIC_KEY
|
||||
);
|
||||
fs.unlinkSync(data.PublicKeyFile);
|
||||
fs.unlinkSync(data.SignatureFile);
|
||||
});
|
||||
|
||||
test('verify sha56 success', ()=> {
|
||||
const hash = fs.readFileSync('test/test_verify_sha256.dat.sha256', {encoding: 'utf8'});
|
||||
return expect(helpers.verifyHash(path.resolve('test/test_verify_sha256.dat'), hash))
|
||||
.resolves.toBe(hash)
|
||||
test('verify sha56 success', () => {
|
||||
const hash = fs.readFileSync('test/test_verify_sha256.dat.sha256', {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
return expect(
|
||||
helpers.verifyHash(path.resolve('test/test_verify_sha256.dat'), hash)
|
||||
).resolves.toBe(hash);
|
||||
});
|
||||
|
||||
test('verify sha56 fail', ()=> {
|
||||
const hash = fs.readFileSync('test/test_verify_sha256.dat.sha256', {encoding: 'utf8'});
|
||||
return expect(helpers.verifyHash(path.resolve('test/test_verify_sha256_fail.dat'), hash))
|
||||
.rejects.toThrow();
|
||||
test('verify sha56 fail', () => {
|
||||
const hash = fs.readFileSync('test/test_verify_sha256.dat.sha256', {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
return expect(
|
||||
helpers.verifyHash(path.resolve('test/test_verify_sha256_fail.dat'), hash)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
@@ -35,12 +35,13 @@ a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--text_color);
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--text_color);
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -52,21 +53,24 @@ p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
white-space: pre;
|
||||
text-align: left;
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
white-space: pre;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--heading_text_color);
|
||||
}
|
||||
|
||||
h2, h3 {
|
||||
color: var(--heading_other_text_color);
|
||||
h2,
|
||||
h3 {
|
||||
color: var(--heading_other_text_color);
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -81,19 +85,23 @@ p {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.scrollable-content, ::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
.scrollable-content,
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.scrollable-content, ::-webkit-scrollbar * {
|
||||
background: transparent;
|
||||
.scrollable-content,
|
||||
::-webkit-scrollbar * {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.scrollable-content, ::-webkit-scrollbar-thumb {
|
||||
background: var(--control_background_hover) !important;
|
||||
.scrollable-content,
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--control_background_hover) !important;
|
||||
}
|
||||
|
||||
.scrollbar-corner, ::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
.scrollbar-corner,
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
20
src/index.js
20
src/index.js
@@ -3,16 +3,16 @@ import 'react-checkbox-tree/lib/react-checkbox-tree.css';
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {Provider} from 'react-redux';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import packageJson from '../package.json';
|
||||
|
||||
import App from './App.jsx';
|
||||
import {setProviderState} from './redux/actions/mount_actions';
|
||||
import {setActiveRelease} from './redux/actions/release_version_actions';
|
||||
import { setProviderState } from './redux/actions/mount_actions';
|
||||
import { setActiveRelease } from './redux/actions/release_version_actions';
|
||||
import createAppStore from './redux/store/createAppStore';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
import {getIPCRenderer} from './utils';
|
||||
import { getIPCRenderer } from './utils.jsx';
|
||||
|
||||
const Constants = require('./constants');
|
||||
|
||||
@@ -45,16 +45,18 @@ if (ipcRenderer) {
|
||||
store.dispatch(setProviderState(provider, state));
|
||||
}
|
||||
store.dispatch(
|
||||
setActiveRelease(result.data.Release, result.data.Version));
|
||||
setActiveRelease(result.data.Release, result.data.Version)
|
||||
);
|
||||
} else {
|
||||
store = createAppStore(platformInfo, packageJson.version, {});
|
||||
}
|
||||
|
||||
ReactDOM.render((
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App/>
|
||||
</Provider>
|
||||
), document.getElementById('root'));
|
||||
<App />
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
serviceWorker.unregister();
|
||||
});
|
||||
ipcRenderer.send(Constants.IPC_Get_State);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
import * as Constants from '../../constants';
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
import {getIPCRenderer} from '../../utils';
|
||||
import { getIPCRenderer } from '../../utils.jsx';
|
||||
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
let yesNoResolvers = [];
|
||||
|
||||
export const confirmYesNo = title => {
|
||||
return dispatch => {
|
||||
return new Promise(resolve => {
|
||||
export const confirmYesNo = (title) => {
|
||||
return (dispatch) => {
|
||||
return new Promise((resolve) => {
|
||||
dispatch(handleConfirmYesNo(true, title, resolve));
|
||||
});
|
||||
};
|
||||
@@ -17,15 +18,12 @@ export const DISPLAY_CONFIRM_YES_NO = 'common/displayConfirmYesNo';
|
||||
const displayConfirmYesNo = (show, title) => {
|
||||
return {
|
||||
type: DISPLAY_CONFIRM_YES_NO,
|
||||
payload: {
|
||||
show,
|
||||
title
|
||||
},
|
||||
payload: { show, title },
|
||||
};
|
||||
};
|
||||
|
||||
export const displaySelectAppPlatform = display => {
|
||||
return dispatch => {
|
||||
export const displaySelectAppPlatform = (display) => {
|
||||
return (dispatch) => {
|
||||
if (display) {
|
||||
dispatch(showWindow());
|
||||
}
|
||||
@@ -34,14 +32,14 @@ export const displaySelectAppPlatform = display => {
|
||||
};
|
||||
};
|
||||
|
||||
export const hideConfirmYesNo = confirmed => {
|
||||
return dispatch => {
|
||||
export const hideConfirmYesNo = (confirmed) => {
|
||||
return (dispatch) => {
|
||||
dispatch(handleConfirmYesNo(false, confirmed));
|
||||
};
|
||||
};
|
||||
|
||||
const handleConfirmYesNo = (show, titleOrConfirmed, resolve) => {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
if (show) {
|
||||
yesNoResolvers.push(resolve);
|
||||
dispatch(displayConfirmYesNo(show, titleOrConfirmed));
|
||||
@@ -57,26 +55,23 @@ export const NOTIFY_APPLICATION_BUSY = 'common/notifyApplicationBusy';
|
||||
export const notifyApplicationBusy = (busy, transparent) => {
|
||||
return {
|
||||
type: NOTIFY_APPLICATION_BUSY,
|
||||
payload: {
|
||||
busy,
|
||||
transparent
|
||||
},
|
||||
payload: { busy, transparent },
|
||||
};
|
||||
};
|
||||
|
||||
export const notifyRebootRequired = createAction('common/notifyRebootRequired');
|
||||
|
||||
export const rebootSystem = () => {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
dispatch(setApplicationReady(false));
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.send(Constants.IPC_Reboot_System);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const saveState = () => {
|
||||
return (dispatch, getState) => {
|
||||
return (_, getState) => {
|
||||
const state = getState();
|
||||
if (state.common.AppReady) {
|
||||
let currentState = {
|
||||
@@ -94,9 +89,7 @@ export const saveState = () => {
|
||||
}
|
||||
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.send(Constants.IPC_Save_State, {
|
||||
State: currentState
|
||||
});
|
||||
ipcRenderer.send(Constants.IPC_Save_State, { State: currentState });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -106,7 +99,7 @@ export const setAllowMount = createAction('common/setAllowMount');
|
||||
export const setApplicationReady = createAction('common/setApplicationReady');
|
||||
|
||||
export const SET_DISPLAY_SELECT_APPPLATFORM = 'common/displaySelectAppPlatform';
|
||||
export const setDisplaySelectAppPlatform = display => {
|
||||
export const setDisplaySelectAppPlatform = (display) => {
|
||||
return {
|
||||
type: SET_DISPLAY_SELECT_APPPLATFORM,
|
||||
payload: display,
|
||||
@@ -116,14 +109,14 @@ export const setDisplaySelectAppPlatform = display => {
|
||||
export const setLinuxAppPlatform = createAction('common/setLinuxAppPlatform');
|
||||
|
||||
export const setRebootRequired = () => {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
dispatch(showWindow());
|
||||
dispatch(notifyRebootRequired(true));
|
||||
};
|
||||
};
|
||||
|
||||
export const showWindow = () => {
|
||||
return dispatch => {
|
||||
return (_) => {
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.send(Constants.IPC_Show_Window);
|
||||
}
|
||||
@@ -131,7 +124,7 @@ export const showWindow = () => {
|
||||
};
|
||||
|
||||
export const shutdownApplication = () => {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
dispatch(setApplicationReady(false));
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.send(Constants.IPC_Shutdown);
|
||||
|
||||
@@ -1,58 +1,76 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
import * as Constants from '../../constants';
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
import {getIPCRenderer} from '../../utils';
|
||||
import {notifyError} from './error_actions';
|
||||
import { getIPCRenderer } from '../../utils.jsx';
|
||||
|
||||
import { notifyError } from './error_actions';
|
||||
import {
|
||||
installAndTestRelease,
|
||||
installDependency,
|
||||
installRelease,
|
||||
installUpgrade
|
||||
installUpgrade,
|
||||
} from './install_actions';
|
||||
|
||||
export const setAllowDownload = createAction('download/setAllowDownload');
|
||||
|
||||
export const SET_DOWNLOAD_BEGIN = 'download/setDownloadBegin';
|
||||
export const setDownloadBegin = (name, type, url) => {
|
||||
return {
|
||||
type: SET_DOWNLOAD_BEGIN,
|
||||
payload: {
|
||||
name,
|
||||
type,
|
||||
url
|
||||
}
|
||||
};
|
||||
return { type: SET_DOWNLOAD_BEGIN, payload: { name, type, url } };
|
||||
};
|
||||
|
||||
export const setDownloadEnd = createAction('download/setDownloadEnd');
|
||||
export const setDownloadProgress = createAction('download/setDownloadProgress');
|
||||
|
||||
export const downloadItem = (name, type, urls, isWinFSP, testVersion, appPlatform) => {
|
||||
export const downloadItem = (
|
||||
name,
|
||||
type,
|
||||
urls,
|
||||
isWinFSP,
|
||||
testVersion,
|
||||
appPlatform
|
||||
) => {
|
||||
return (dispatch, getState) => {
|
||||
if (!Array.isArray(urls)) {
|
||||
urls = [urls];
|
||||
}
|
||||
|
||||
const downloadComplete = result => {
|
||||
const downloadComplete = (result) => {
|
||||
if (result.Success) {
|
||||
switch (type) {
|
||||
case Constants.INSTALL_TYPES.Dependency:
|
||||
dispatch(installDependency(result.Destination, result.URL, isWinFSP));
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.Release:
|
||||
dispatch(installRelease(result.Destination));
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.TestRelease:
|
||||
dispatch(installAndTestRelease(result.Destination, testVersion, appPlatform));
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.Upgrade:
|
||||
//const info = this.props.LocationsLookup[this.props.AppPlatform][this.props.VersionLookup[this.props.AppPlatform][0]];
|
||||
const sha256 = null;//info.sha256;
|
||||
const signature = null;//info.sig;
|
||||
dispatch(installUpgrade(result.Destination, sha256, signature, !!result.SkipVerification));
|
||||
break;
|
||||
default:
|
||||
dispatch(notifyError('Unknown download type: ' + type));
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.Dependency:
|
||||
dispatch(
|
||||
installDependency(result.Destination, result.URL, isWinFSP)
|
||||
);
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.Release:
|
||||
dispatch(installRelease(result.Destination));
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.TestRelease:
|
||||
dispatch(
|
||||
installAndTestRelease(
|
||||
result.Destination,
|
||||
testVersion,
|
||||
appPlatform
|
||||
)
|
||||
);
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.Upgrade:
|
||||
// const info =
|
||||
// this.props.LocationsLookup[this.props.AppPlatform][this.props.VersionLookup[this.props.AppPlatform][0]];
|
||||
const sha256 = null; // info.sha256;
|
||||
const signature = null; // info.sig;
|
||||
dispatch(
|
||||
installUpgrade(
|
||||
result.Destination,
|
||||
sha256,
|
||||
signature,
|
||||
!!result.SkipVerification
|
||||
)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
dispatch(notifyError('Unknown download type: ' + type));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (type === Constants.INSTALL_TYPES.TestRelease) {
|
||||
@@ -62,10 +80,13 @@ export const downloadItem = (name, type, urls, isWinFSP, testVersion, appPlatfor
|
||||
}
|
||||
};
|
||||
|
||||
const downloadAtIndex = index => {
|
||||
const downloadAtIndex = (index) => {
|
||||
const url = urls[index];
|
||||
const state = getState();
|
||||
if ((index > 0) || (!state.download.DownloadActive && state.download.AllowDownload)) {
|
||||
if (
|
||||
index > 0 ||
|
||||
(!state.download.DownloadActive && state.download.AllowDownload)
|
||||
) {
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
if (ipcRenderer) {
|
||||
dispatch(setDownloadBegin(name, type, url));
|
||||
@@ -75,8 +96,11 @@ export const downloadItem = (name, type, urls, isWinFSP, testVersion, appPlatfor
|
||||
};
|
||||
|
||||
const downloadFileComplete = (_, arg) => {
|
||||
ipcRenderer.removeListener(Constants.IPC_Download_File_Progress, downloadFileProgress);
|
||||
if (!arg.data.Success && (++index < urls.length)) {
|
||||
ipcRenderer.removeListener(
|
||||
Constants.IPC_Download_File_Progress,
|
||||
downloadFileProgress
|
||||
);
|
||||
if (!arg.data.Success && ++index < urls.length) {
|
||||
downloadAtIndex(index);
|
||||
} else {
|
||||
downloadComplete(arg.data);
|
||||
@@ -84,8 +108,14 @@ export const downloadItem = (name, type, urls, isWinFSP, testVersion, appPlatfor
|
||||
}
|
||||
};
|
||||
|
||||
ipcRenderer.on(Constants.IPC_Download_File_Progress, downloadFileProgress);
|
||||
ipcRenderer.once(Constants.IPC_Download_File_Complete, downloadFileComplete);
|
||||
ipcRenderer.on(
|
||||
Constants.IPC_Download_File_Progress,
|
||||
downloadFileProgress
|
||||
);
|
||||
ipcRenderer.once(
|
||||
Constants.IPC_Download_File_Complete,
|
||||
downloadFileComplete
|
||||
);
|
||||
|
||||
ipcRenderer.send(Constants.IPC_Download_File, {
|
||||
Filename: name,
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
showWindow,
|
||||
shutdownApplication
|
||||
} from './common_actions';
|
||||
import { showWindow, shutdownApplication } from './common_actions';
|
||||
|
||||
let ErrorActions = [];
|
||||
|
||||
@@ -36,13 +33,13 @@ export const dismissError = () => {
|
||||
};
|
||||
|
||||
export const dismissInfo = () => {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
dispatch(clearInfo());
|
||||
};
|
||||
};
|
||||
|
||||
export const notifyError = (msg, critical, callback) => {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
ErrorActions = [callback, ...ErrorActions];
|
||||
msg = msg ? msg.toString() : 'Unknown Error';
|
||||
dispatch(setErrorInfo(msg, critical));
|
||||
@@ -51,7 +48,7 @@ export const notifyError = (msg, critical, callback) => {
|
||||
};
|
||||
|
||||
export const notifyInfo = (title, msg) => {
|
||||
return dispatch => {
|
||||
return (dispatch) => {
|
||||
title = title ? title.toString() : 'Information';
|
||||
msg = msg ? msg.toString() : '';
|
||||
dispatch(setInfo(title, msg));
|
||||
@@ -60,23 +57,10 @@ export const notifyInfo = (title, msg) => {
|
||||
|
||||
export const SET_ERROR_INFO = 'error/setErrorInfo';
|
||||
export const setErrorInfo = (msg, critical) => {
|
||||
return {
|
||||
type: SET_ERROR_INFO,
|
||||
payload: {
|
||||
msg,
|
||||
critical
|
||||
}
|
||||
}
|
||||
return { type: SET_ERROR_INFO, payload: { msg, critical } };
|
||||
};
|
||||
|
||||
|
||||
export const SET_INFO = 'error/setInfo';
|
||||
export const setInfo = (title, msg) => {
|
||||
return {
|
||||
type: SET_INFO,
|
||||
payload: {
|
||||
title,
|
||||
msg
|
||||
}
|
||||
}
|
||||
return { type: SET_INFO, payload: { title, msg } };
|
||||
};
|
||||
@@ -1,18 +1,8 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
import * as Constants from '../../constants';
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
import {
|
||||
getIPCRenderer,
|
||||
getSelectedVersionFromState
|
||||
} from '../../utils';
|
||||
import {notifyError} from './error_actions';
|
||||
import {downloadItem, setAllowDownload} from './download_actions';
|
||||
import {
|
||||
loadReleases,
|
||||
setActiveRelease,
|
||||
setInstalledVersion,
|
||||
setReleaseUpgradeAvailable,
|
||||
setNewReleasesAvailable2,
|
||||
} from './release_version_actions';
|
||||
import { getIPCRenderer, getSelectedVersionFromState } from '../../utils.jsx';
|
||||
|
||||
import {
|
||||
confirmYesNo,
|
||||
displaySelectAppPlatform,
|
||||
@@ -21,18 +11,28 @@ import {
|
||||
setLinuxAppPlatform,
|
||||
setRebootRequired,
|
||||
showWindow,
|
||||
shutdownApplication
|
||||
shutdownApplication,
|
||||
} from './common_actions';
|
||||
import {unmountAll} from './mount_actions';
|
||||
import { downloadItem, setAllowDownload } from './download_actions';
|
||||
import { notifyError } from './error_actions';
|
||||
import { unmountAll } from './mount_actions';
|
||||
import {
|
||||
loadReleases,
|
||||
setActiveRelease,
|
||||
setInstalledVersion,
|
||||
setNewReleasesAvailable2,
|
||||
setReleaseUpgradeAvailable,
|
||||
} from './release_version_actions';
|
||||
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
|
||||
export const checkInstalled = (dependencies, version) => {
|
||||
return (dispatch, getState) => {
|
||||
const checkInstalledComplete = (event, arg) => {
|
||||
const checkInstalledComplete = (_, arg) => {
|
||||
const result = arg.data;
|
||||
const updateState = () => {
|
||||
const installedVersion = result.Success && result.Exists ? result.Version : 'none';
|
||||
const installedVersion =
|
||||
result.Success && result.Exists ? result.Version : 'none';
|
||||
const state = getState();
|
||||
|
||||
const release = state.relver.Release;
|
||||
@@ -40,7 +40,9 @@ export const checkInstalled = (dependencies, version) => {
|
||||
|
||||
let upgradeAvailable = false;
|
||||
if (installedVersion !== 'none') {
|
||||
const latestVersion = state.relver.VersionLookup[Constants.RELEASE_TYPES[release]].length - 1;
|
||||
const latestVersion =
|
||||
state.relver.VersionLookup[Constants.RELEASE_TYPES[release]]
|
||||
.length - 1;
|
||||
if (version === -1) {
|
||||
version = latestVersion;
|
||||
dispatch(setActiveRelease(release, version));
|
||||
@@ -57,14 +59,18 @@ export const checkInstalled = (dependencies, version) => {
|
||||
const autoInstallRelease = getState().install.AutoInstallRelease;
|
||||
dispatch(setAutoInstallRelease(false));
|
||||
|
||||
if (result.Dependencies && (result.Dependencies.length > 0)) {
|
||||
if (result.Dependencies && result.Dependencies.length > 0) {
|
||||
dispatch(showWindow());
|
||||
} else if ((installedVersion === 'none') && autoInstallRelease) {
|
||||
} else if (installedVersion === 'none' && autoInstallRelease) {
|
||||
dispatch(setAllowMount(false));
|
||||
const versionString = getState().relver.VersionLookup[Constants.RELEASE_TYPES[release]][version];
|
||||
const versionString = getState().relver.VersionLookup[
|
||||
Constants.RELEASE_TYPES[release]
|
||||
][version];
|
||||
const urls = getState().relver.LocationsLookup[versionString].urls;
|
||||
const fileName = versionString + '.zip';
|
||||
dispatch(downloadItem(fileName, Constants.INSTALL_TYPES.Release, urls));
|
||||
dispatch(
|
||||
downloadItem(fileName, Constants.INSTALL_TYPES.Release, urls)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,7 +81,10 @@ export const checkInstalled = (dependencies, version) => {
|
||||
}
|
||||
};
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Check_Installed_Reply, checkInstalledComplete);
|
||||
ipcRenderer.once(
|
||||
Constants.IPC_Check_Installed_Reply,
|
||||
checkInstalledComplete
|
||||
);
|
||||
ipcRenderer.send(Constants.IPC_Check_Installed, {
|
||||
Dependencies: dependencies,
|
||||
Version: version,
|
||||
@@ -89,10 +98,14 @@ export const checkVersionInstalled = () => {
|
||||
|
||||
dispatch(setAllowDownload(false));
|
||||
const selectedVersion = getSelectedVersionFromState(state);
|
||||
if (selectedVersion && (selectedVersion !== 'unavailable')) {
|
||||
if (selectedVersion && selectedVersion !== 'unavailable') {
|
||||
let dependencies = [];
|
||||
if (state.relver.LocationsLookup[selectedVersion] && state.relver.LocationsLookup[selectedVersion].dependencies) {
|
||||
dependencies = state.relver.LocationsLookup[selectedVersion].dependencies;
|
||||
if (
|
||||
state.relver.LocationsLookup[selectedVersion] &&
|
||||
state.relver.LocationsLookup[selectedVersion].dependencies
|
||||
) {
|
||||
dependencies =
|
||||
state.relver.LocationsLookup[selectedVersion].dependencies;
|
||||
}
|
||||
dispatch(checkInstalled(dependencies, selectedVersion));
|
||||
} else {
|
||||
@@ -107,9 +120,9 @@ export const installDependency = (source, url, isWinFSP) => {
|
||||
if (ipcRenderer && !getState().install.InstallActive) {
|
||||
dispatch(setInstallActive(Constants.INSTALL_TYPES.Dependency));
|
||||
|
||||
const installDependencyComplete = (event, arg) => {
|
||||
const installDependencyComplete = (_, arg) => {
|
||||
const result = arg.data;
|
||||
const handleCompleted = ()=> {
|
||||
const handleCompleted = () => {
|
||||
if (result.RebootRequired) {
|
||||
dispatch(setRebootRequired());
|
||||
} else {
|
||||
@@ -122,13 +135,16 @@ export const installDependency = (source, url, isWinFSP) => {
|
||||
};
|
||||
|
||||
if (result.Success && source.toLowerCase().endsWith('.dmg')) {
|
||||
const dep = getState().install.MissingDependencies.find(d => {
|
||||
const dep = getState().install.MissingDependencies.find((d) => {
|
||||
return d.download === url;
|
||||
});
|
||||
const i = setInterval(()=> {
|
||||
const ret = ipcRenderer.sendSync(Constants.IPC_Check_Dependency_Installed + '_sync', {
|
||||
File: dep.file,
|
||||
});
|
||||
const i = setInterval(() => {
|
||||
const ret = ipcRenderer.sendSync(
|
||||
Constants.IPC_Check_Dependency_Installed + '_sync',
|
||||
{
|
||||
File: dep.file,
|
||||
}
|
||||
);
|
||||
|
||||
if (ret.data.Exists) {
|
||||
clearInterval(i);
|
||||
@@ -142,7 +158,10 @@ export const installDependency = (source, url, isWinFSP) => {
|
||||
}
|
||||
};
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Install_Dependency_Reply, installDependencyComplete);
|
||||
ipcRenderer.once(
|
||||
Constants.IPC_Install_Dependency_Reply,
|
||||
installDependencyComplete
|
||||
);
|
||||
ipcRenderer.send(Constants.IPC_Install_Dependency, {
|
||||
Source: source,
|
||||
URL: url,
|
||||
@@ -160,7 +179,7 @@ export const installAndTestRelease = (source, version, appPlatform) => {
|
||||
FilePath: source,
|
||||
});
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Test_Release_Reply, (event, arg) => {
|
||||
ipcRenderer.once(Constants.IPC_Test_Release_Reply, (_, arg) => {
|
||||
if (arg.data.Success) {
|
||||
ipcRenderer.sendSync(Constants.IPC_Set_Linux_AppPlatform, {
|
||||
AppPlatform: appPlatform,
|
||||
@@ -177,10 +196,13 @@ export const installAndTestRelease = (source, version, appPlatform) => {
|
||||
});
|
||||
ipcRenderer.send(Constants.IPC_Test_Release, {
|
||||
Version: version,
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Extract_Release_Complete, extractReleaseComplete);
|
||||
ipcRenderer.once(
|
||||
Constants.IPC_Extract_Release_Complete,
|
||||
extractReleaseComplete
|
||||
);
|
||||
ipcRenderer.send(Constants.IPC_Extract_Release, {
|
||||
Source: source,
|
||||
Version: version,
|
||||
@@ -192,7 +214,10 @@ export const installAndTestRelease = (source, version, appPlatform) => {
|
||||
export const installReleaseByVersion = (release, version) => {
|
||||
return (dispatch, getState) => {
|
||||
const install = () => {
|
||||
if (getState().download.AllowDownload && !getState().download.DownloadActive) {
|
||||
if (
|
||||
getState().download.AllowDownload &&
|
||||
!getState().download.DownloadActive
|
||||
) {
|
||||
dispatch(setAutoInstallRelease(true));
|
||||
dispatch(setActiveRelease(release, version));
|
||||
} else {
|
||||
@@ -202,31 +227,34 @@ export const installReleaseByVersion = (release, version) => {
|
||||
|
||||
if (getState().mounts.MountsBusy) {
|
||||
dispatch(confirmYesNo('Unmount all drives?'))
|
||||
.then(confirmed => {
|
||||
.then((confirmed) => {
|
||||
if (confirmed) {
|
||||
dispatch(unmountAll(install));
|
||||
}
|
||||
})
|
||||
.catch(error => notifyError(error));
|
||||
.catch((error) => notifyError(error));
|
||||
} else {
|
||||
install();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const installRelease = source => {
|
||||
export const installRelease = (source) => {
|
||||
return (dispatch, getState) => {
|
||||
if (ipcRenderer && !getState().install.InstallActive) {
|
||||
dispatch(setInstallActive(Constants.INSTALL_TYPES.Release));
|
||||
|
||||
const version = getSelectedVersionFromState(getState());
|
||||
const extractReleaseComplete = (event, arg) => {
|
||||
const extractReleaseComplete = (_, arg) => {
|
||||
ipcRenderer.send(Constants.IPC_Delete_File, {
|
||||
FilePath: source,
|
||||
});
|
||||
|
||||
if (arg.data.Success) {
|
||||
localStorage.setItem('previous_releases', localStorage.getItem('releases'));
|
||||
localStorage.setItem(
|
||||
'previous_releases',
|
||||
localStorage.getItem('releases')
|
||||
);
|
||||
dispatch(setNewReleasesAvailable2([]));
|
||||
}
|
||||
|
||||
@@ -234,7 +262,10 @@ export const installRelease = source => {
|
||||
dispatch(checkVersionInstalled());
|
||||
};
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Extract_Release_Complete, extractReleaseComplete);
|
||||
ipcRenderer.once(
|
||||
Constants.IPC_Extract_Release_Complete,
|
||||
extractReleaseComplete
|
||||
);
|
||||
ipcRenderer.send(Constants.IPC_Extract_Release, {
|
||||
Source: source,
|
||||
Version: version,
|
||||
@@ -249,23 +280,33 @@ export const installUpgrade = (source, sha256, signature, skipVerification) => {
|
||||
dispatch(setInstallActive(Constants.INSTALL_TYPES.Upgrade));
|
||||
dispatch(setApplicationReady(false));
|
||||
|
||||
const installUpgradeComplete = (event, arg) => {
|
||||
const installUpgradeComplete = (_, arg) => {
|
||||
const result = arg.data;
|
||||
if (result.Success) {
|
||||
dispatch(shutdownApplication());
|
||||
} else {
|
||||
dispatch(setApplicationReady(true));
|
||||
dispatch(setInstallComplete(result));
|
||||
dispatch(notifyError(result.Error, false, () => {
|
||||
// TODO Prompt to verify
|
||||
if (result.AllowSkipVerification) {
|
||||
dispatch(installUpgrade(source, sha256, signature, true));
|
||||
}
|
||||
}, false));
|
||||
dispatch(
|
||||
notifyError(
|
||||
result.Error,
|
||||
false,
|
||||
() => {
|
||||
// TODO Prompt to verify
|
||||
if (result.AllowSkipVerification) {
|
||||
dispatch(installUpgrade(source, sha256, signature, true));
|
||||
}
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Install_Upgrade_Reply, installUpgradeComplete);
|
||||
ipcRenderer.once(
|
||||
Constants.IPC_Install_Upgrade_Reply,
|
||||
installUpgradeComplete
|
||||
);
|
||||
ipcRenderer.send(Constants.IPC_Install_Upgrade, {
|
||||
Sha256: sha256,
|
||||
Signature: signature,
|
||||
@@ -276,9 +317,17 @@ export const installUpgrade = (source, sha256, signature, skipVerification) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const setAutoInstallRelease = createAction('install/setAutoInstallRelease');
|
||||
export const setDismissDependencies = createAction('install/setDismissDependencies');
|
||||
export const setAutoInstallRelease = createAction(
|
||||
'install/setAutoInstallRelease'
|
||||
);
|
||||
export const setDismissDependencies = createAction(
|
||||
'install/setDismissDependencies'
|
||||
);
|
||||
export const setInstallActive = createAction('install/setInstallActive');
|
||||
export const setInstallTestActive = createAction('install/setInstallTestActive');
|
||||
export const setInstallTestActive = createAction(
|
||||
'install/setInstallTestActive'
|
||||
);
|
||||
export const setInstallComplete = createAction('install/setInstallComplete');
|
||||
export const setMissingDependencies = createAction('install/setMissingDependencies');
|
||||
export const setMissingDependencies = createAction(
|
||||
'install/setMissingDependencies'
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
|
||||
import * as Constants from '../../constants';
|
||||
import {getIPCRenderer} from '../../utils';
|
||||
import {getIPCRenderer} from '../../utils.jsx';
|
||||
|
||||
import {confirmYesNo, saveState} from './common_actions';
|
||||
import {notifyError} from './error_actions';
|
||||
@@ -23,8 +23,10 @@ export const addRemoteMount = (hostNameOrIp, port, token) => {
|
||||
Version: getState().relver.InstalledVersion,
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
notifyError('Failed to set \'RemoteToken\': ' + arg.data.Error));
|
||||
dispatch(noti
|
||||
'Failed to set \'RemoteToken\': '
|
||||
oken
|
||||
': " + arg.data.Error));
|
||||
dispatch(setBusy(false));
|
||||
}
|
||||
});
|
||||
@@ -43,7 +45,14 @@ export const addRemoteMount = (hostNameOrIp, port, token) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const addS3Mount = (name, accessKey, secretKey, region, bucketName, url) => {
|
||||
export const addS3Mount = (
|
||||
name,
|
||||
accessKey,
|
||||
secretKey,
|
||||
region,
|
||||
bucketName,
|
||||
url
|
||||
) => {
|
||||
return (dispatch, getState) => {
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
const provider = 'S3' + name;
|
||||
@@ -60,7 +69,8 @@ export const addS3Mount = (name, accessKey, secretKey, region, bucketName, url)
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
notifyError('Failed to create S3 instance: ' + arg.data.Error));
|
||||
notifyError('Failed to create S3 instance: ' + arg.data.Error)
|
||||
);
|
||||
dispatch(setBusy(false));
|
||||
}
|
||||
});
|
||||
@@ -95,11 +105,12 @@ export const displayConfiguration = (provider, remote, s3) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const removeMount = provider => {
|
||||
return dispatch => {
|
||||
export const removeMount = (provider) => {
|
||||
return (dispatch) => {
|
||||
const isRemote = provider.startsWith('Remote');
|
||||
dispatch(confirmYesNo('Delete [' + provider.substr(isRemote ? 6 : 2) + ']?'))
|
||||
.then(confirmed => {
|
||||
dispatch(
|
||||
confirmYesNo('Delete [' + provider.substr(isRemote ? 6 : 2) + ']?')
|
||||
).then((confirmed) => {
|
||||
if (confirmed) {
|
||||
dispatch(removeMount2(provider));
|
||||
}
|
||||
@@ -107,8 +118,8 @@ export const removeMount = provider => {
|
||||
};
|
||||
};
|
||||
|
||||
const removeMount2 = provider => {
|
||||
return dispatch => {
|
||||
const removeMount2 = (provider) => {
|
||||
return (dispatch) => {
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
ipcRenderer.once(Constants.IPC_Remove_Mount_Reply, (_, arg) => {
|
||||
if (arg.data.Success) {
|
||||
@@ -119,7 +130,7 @@ const removeMount2 = provider => {
|
||||
const isRemote = provider.startsWith('Remote');
|
||||
ipcRenderer.send(Constants.IPC_Remove_Mount, {
|
||||
Remote: isRemote,
|
||||
Name: provider.substr(isRemote ? 6 : 2)
|
||||
Name: provider.substr(isRemote ? 6 : 2),
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -128,15 +139,13 @@ export const removeMount3 = createAction('mounts/removeMount3');
|
||||
|
||||
export const RESET_MOUNTS_STATE = 'mounts/resetMountsState';
|
||||
export const resetMountsState = () => {
|
||||
return {type: RESET_MOUNTS_STATE, payload: null,}
|
||||
return {type: RESET_MOUNTS_STATE, payload: null};
|
||||
};
|
||||
|
||||
export const SET_ALLOW_MOUNT = 'mounts/setAllowMount';
|
||||
export const setAllowMount =
|
||||
(provider,
|
||||
allow) => {
|
||||
return {type: SET_ALLOW_MOUNT, payload: {provider, allow}};
|
||||
};
|
||||
export const setAllowMount = (provider, allow) => {
|
||||
return {type: SET_ALLOW_MOUNT, payload: {provider, allow}};
|
||||
};
|
||||
|
||||
export const SET_AUTO_MOUNT_PROCESSED = 'mounts/setAutoMountProcessed';
|
||||
export const setAutoMountProcessed = (provider, processed) => {
|
||||
@@ -146,26 +155,22 @@ export const setAutoMountProcessed = (provider, processed) => {
|
||||
export const setBusy = createAction('mounts/setBusy');
|
||||
|
||||
export const SET_MOUNT_STATE = 'mounts/setMountState';
|
||||
export const setMountState =
|
||||
(provider,
|
||||
state) => {
|
||||
return {type: SET_MOUNT_STATE, payload: {provider, state}};
|
||||
};
|
||||
export const setMountState = (provider, state) => {
|
||||
return {type: SET_MOUNT_STATE, payload: {provider, state}};
|
||||
};
|
||||
|
||||
export const SET_MOUNTED = 'mounts/setMounted';
|
||||
export const setMounted =
|
||||
(provider,
|
||||
mounted) => {
|
||||
return {type: SET_MOUNTED, payload: {provider, mounted}};
|
||||
};
|
||||
export const setMounted = (provider, mounted) => {
|
||||
return {type: SET_MOUNTED, payload: {provider, mounted}};
|
||||
};
|
||||
|
||||
export const SET_PROVIDER_STATE = 'mounts/setProviderState';
|
||||
export const setProviderState = (provider, state) => {
|
||||
return {type: SET_PROVIDER_STATE, payload: {provider, state}}
|
||||
return {type: SET_PROVIDER_STATE, payload: {provider, state}};
|
||||
};
|
||||
|
||||
export const unmountAll = completedCallback => {
|
||||
return dispatch => {
|
||||
export const unmountAll = (completedCallback) => {
|
||||
return (dispatch) => {
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
const unmountedCallback = () => {
|
||||
dispatch(resetMountsState());
|
||||
@@ -173,5 +178,5 @@ export const unmountAll = completedCallback => {
|
||||
};
|
||||
ipcRenderer.once(Constants.IPC_Unmount_All_Drives_Reply, unmountedCallback);
|
||||
ipcRenderer.send(Constants.IPC_Unmount_All_Drives);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
export const displayPinnedManager = createAction('pinned/displayPinnedManager');
|
||||
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import axios from 'axios';
|
||||
|
||||
import * as Constants from '../../constants';
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
import {notifyError} from './error_actions';
|
||||
import {
|
||||
checkNewReleases,
|
||||
getIPCRenderer,
|
||||
getNewReleases,
|
||||
getSelectedVersionFromState,
|
||||
} from '../../utils.jsx';
|
||||
|
||||
import {
|
||||
saveState,
|
||||
setAllowMount,
|
||||
setApplicationReady,
|
||||
showWindow
|
||||
showWindow,
|
||||
} from './common_actions';
|
||||
import { notifyError } from './error_actions';
|
||||
import {
|
||||
checkVersionInstalled,
|
||||
setDismissDependencies
|
||||
setDismissDependencies,
|
||||
} from './install_actions';
|
||||
import {unmountAll} from './mount_actions';
|
||||
import {
|
||||
checkNewReleases,
|
||||
getIPCRenderer,
|
||||
getNewReleases, getSelectedVersionFromState
|
||||
} from '../../utils';
|
||||
import { unmountAll } from './mount_actions';
|
||||
|
||||
export const CLEAR_UI_UPGRADE = 'relver/clearUIUpgrade';
|
||||
export const clearUIUpgrade = () => {
|
||||
@@ -27,12 +30,12 @@ export const clearUIUpgrade = () => {
|
||||
};
|
||||
};
|
||||
|
||||
const cleanupOldReleases = versionList => {
|
||||
return dispatch => {
|
||||
const cleanupOldReleases = (versionList) => {
|
||||
return (_) => {
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.sendSync(Constants.IPC_Cleanup_Releases + '_sync', {
|
||||
version_list: versionList
|
||||
version_list: versionList,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -42,55 +45,74 @@ export const detectUIUpgrade = () => {
|
||||
return (dispatch, getState) => {
|
||||
axios
|
||||
.get(Constants.UI_RELEASES_URL)
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
const state = getState();
|
||||
const appPlatform = state.common.AppPlatform;
|
||||
const version = state.common.Version;
|
||||
const data = response.data;
|
||||
|
||||
if (data.Versions &&
|
||||
if (
|
||||
data.Versions &&
|
||||
data.Versions[appPlatform] &&
|
||||
(data.Versions[appPlatform].length > 0) &&
|
||||
(data.Versions[appPlatform][0] !== version)) {
|
||||
dispatch(setUIUpgradeData(data.Locations[appPlatform][data.Versions[appPlatform][0]], data.Versions[appPlatform][0]));
|
||||
data.Versions[appPlatform].length > 0 &&
|
||||
data.Versions[appPlatform][0] !== version
|
||||
) {
|
||||
dispatch(
|
||||
setUIUpgradeData(
|
||||
data.Locations[appPlatform][data.Versions[appPlatform][0]],
|
||||
data.Versions[appPlatform][0]
|
||||
)
|
||||
);
|
||||
if (!state.relver.UpgradeDismissed) {
|
||||
dispatch(showWindow());
|
||||
}
|
||||
} else {
|
||||
dispatch(clearUIUpgrade());
|
||||
}
|
||||
}).catch(() => {
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(clearUIUpgrade());
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const loadReleases = () => {
|
||||
return (dispatch, getState) => {
|
||||
const dispatchActions = (locationsLookup, versionLookup)=> {
|
||||
const dispatchActions = (locationsLookup, versionLookup) => {
|
||||
const state = getState().relver;
|
||||
let release = state.Release;
|
||||
if (release >= Constants.RELEASE_TYPES.length) {
|
||||
release = Constants.DEFAULT_RELEASE;
|
||||
}
|
||||
|
||||
let latestVersion = versionLookup[Constants.RELEASE_TYPES[release]].length - 1;
|
||||
let latestVersion =
|
||||
versionLookup[Constants.RELEASE_TYPES[release]].length - 1;
|
||||
let version = state.Version;
|
||||
if (versionLookup[Constants.RELEASE_TYPES[release]][0] === 'unavailable') {
|
||||
if (
|
||||
versionLookup[Constants.RELEASE_TYPES[release]][0] === 'unavailable'
|
||||
) {
|
||||
release = Constants.DEFAULT_RELEASE;
|
||||
version = latestVersion = versionLookup[Constants.RELEASE_TYPES[release]].length - 1
|
||||
} else if ((version === -1) || !versionLookup[Constants.RELEASE_TYPES[release]][version]) {
|
||||
version = latestVersion =
|
||||
versionLookup[Constants.RELEASE_TYPES[release]].length - 1;
|
||||
} else if (
|
||||
version === -1 ||
|
||||
!versionLookup[Constants.RELEASE_TYPES[release]][version]
|
||||
) {
|
||||
version = latestVersion;
|
||||
}
|
||||
|
||||
dispatch(setReleaseData(locationsLookup, versionLookup));
|
||||
|
||||
const dispatchActions = (processAllowDismiss = true) => {
|
||||
dispatch(setReleaseUpgradeAvailable((version !== latestVersion)));
|
||||
dispatch(setReleaseUpgradeAvailable(version !== latestVersion));
|
||||
dispatch(setApplicationReady(true));
|
||||
dispatch(detectUIUpgrade());
|
||||
if (processAllowDismiss) {
|
||||
dispatch(setAllowDismissDependencies(versionLookup[Constants.RELEASE_TYPES[release]].length > 1));
|
||||
dispatch(
|
||||
setAllowDismissDependencies(
|
||||
versionLookup[Constants.RELEASE_TYPES[release]].length > 1
|
||||
)
|
||||
);
|
||||
}
|
||||
dispatch(checkVersionInstalled());
|
||||
|
||||
@@ -98,16 +120,18 @@ export const loadReleases = () => {
|
||||
for (const key of Object.keys(locationsLookup)) {
|
||||
versionList.push(key);
|
||||
}
|
||||
dispatch(cleanupOldReleases(versionList))
|
||||
dispatch(cleanupOldReleases(versionList));
|
||||
};
|
||||
|
||||
if ((version !== state.Version) || (release !== state.Release)) {
|
||||
dispatch(unmountAll(() => {
|
||||
dispatch(setActiveRelease(release, version));
|
||||
dispatchActions(false);
|
||||
dispatch(showWindow());
|
||||
dispatch(saveState());
|
||||
}));
|
||||
if (version !== state.Version || release !== state.Release) {
|
||||
dispatch(
|
||||
unmountAll(() => {
|
||||
dispatch(setActiveRelease(release, version));
|
||||
dispatchActions(false);
|
||||
dispatch(showWindow());
|
||||
dispatch(saveState());
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatchActions();
|
||||
}
|
||||
@@ -115,7 +139,7 @@ export const loadReleases = () => {
|
||||
|
||||
axios
|
||||
.get(Constants.RELEASES_URL)
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
const appPlatform = getState().common.AppPlatform;
|
||||
const versionLookup = {
|
||||
Release: response.data.Versions.Release[appPlatform],
|
||||
@@ -129,14 +153,21 @@ export const loadReleases = () => {
|
||||
|
||||
const storedReleases = localStorage.getItem('releases');
|
||||
let newReleases = [];
|
||||
if (storedReleases && (storedReleases.length > 0)) {
|
||||
newReleases = getNewReleases(JSON.parse(storedReleases).VersionLookup, versionLookup, getSelectedVersionFromState(getState()));
|
||||
if (storedReleases && storedReleases.length > 0) {
|
||||
newReleases = getNewReleases(
|
||||
JSON.parse(storedReleases).VersionLookup,
|
||||
versionLookup,
|
||||
getSelectedVersionFromState(getState())
|
||||
);
|
||||
}
|
||||
|
||||
localStorage.setItem('releases', JSON.stringify({
|
||||
LocationsLookup: locationsLookup,
|
||||
VersionLookup: versionLookup
|
||||
}));
|
||||
localStorage.setItem(
|
||||
'releases',
|
||||
JSON.stringify({
|
||||
LocationsLookup: locationsLookup,
|
||||
VersionLookup: versionLookup,
|
||||
})
|
||||
);
|
||||
dispatchActions(locationsLookup, versionLookup);
|
||||
|
||||
dispatch(setNewReleasesAvailable(newReleases));
|
||||
@@ -144,12 +175,17 @@ export const loadReleases = () => {
|
||||
dispatch(setNewReleasesAvailable2(newReleases));
|
||||
localStorage.setItem('previous_releases', storedReleases);
|
||||
dispatch(showWindow());
|
||||
} else if ((newReleases = checkNewReleases(getSelectedVersionFromState(getState()))).length > 0) {
|
||||
} else if (
|
||||
(newReleases = checkNewReleases(
|
||||
getSelectedVersionFromState(getState())
|
||||
)).length > 0
|
||||
) {
|
||||
dispatch(setNewReleasesAvailable2(newReleases));
|
||||
}
|
||||
}).catch(error => {
|
||||
})
|
||||
.catch((error) => {
|
||||
const releases = localStorage.getItem('releases');
|
||||
if (releases && (releases.length > 0)) {
|
||||
if (releases && releases.length > 0) {
|
||||
const obj = JSON.parse(releases);
|
||||
const locationsLookup = obj.LocationsLookup;
|
||||
const versionLookup = obj.VersionLookup;
|
||||
@@ -166,10 +202,7 @@ export const NOTIFY_ACTIVE_RELEASE = 'relver/notifyActiveRelease';
|
||||
export const notifyActiveRelease = (release, version) => {
|
||||
return {
|
||||
type: NOTIFY_ACTIVE_RELEASE,
|
||||
payload: {
|
||||
release: release,
|
||||
version: version
|
||||
},
|
||||
payload: { release: release, version: version },
|
||||
};
|
||||
};
|
||||
|
||||
@@ -183,7 +216,7 @@ export const setActiveRelease = (release, version) => {
|
||||
version = -1;
|
||||
}
|
||||
const versions = relver.VersionLookup[Constants.RELEASE_TYPES[release]];
|
||||
dispatch(setAllowDismissDependencies(versions && (versions.length > 1)));
|
||||
dispatch(setAllowDismissDependencies(versions && versions.length > 1));
|
||||
dispatch(setDismissDependencies(false));
|
||||
dispatch(notifyActiveRelease(release, version));
|
||||
if (common.AppReady) {
|
||||
@@ -192,25 +225,35 @@ export const setActiveRelease = (release, version) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const setAllowDismissDependencies = createAction('relver/setAllowDismissDependencies');
|
||||
export const setDismissNewReleasesAvailable = createAction('relver/setDismissNewReleasesAvailable');
|
||||
export const setAllowDismissDependencies = createAction(
|
||||
'relver/setAllowDismissDependencies'
|
||||
);
|
||||
export const setDismissNewReleasesAvailable = createAction(
|
||||
'relver/setDismissNewReleasesAvailable'
|
||||
);
|
||||
export const setDismissUIUpgrade = createAction('relver/setDismissUIUpgrade');
|
||||
export const setInstalledVersion = createAction('relver/setInstalledVersion');
|
||||
export const setNewReleasesAvailable = createAction('relver/setNewReleasesAvailable');
|
||||
export const setNewReleasesAvailable2 = createAction('relver/setNewReleasesAvailable2');
|
||||
export const setNewReleasesAvailable = createAction(
|
||||
'relver/setNewReleasesAvailable'
|
||||
);
|
||||
export const setNewReleasesAvailable2 = createAction(
|
||||
'relver/setNewReleasesAvailable2'
|
||||
);
|
||||
|
||||
export const SET_RELEASE_DATA = 'relver/setReleaseData';
|
||||
export const setReleaseData = (locationsLookup, versionLookup)=> {
|
||||
export const setReleaseData = (locationsLookup, versionLookup) => {
|
||||
return {
|
||||
type: SET_RELEASE_DATA,
|
||||
payload: {
|
||||
locations: locationsLookup,
|
||||
versions: versionLookup,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const setReleaseUpgradeAvailable = createAction('relver/setReleaseUpgradeAvailable');
|
||||
export const setReleaseUpgradeAvailable = createAction(
|
||||
'relver/setReleaseUpgradeAvailable'
|
||||
);
|
||||
|
||||
export const SET_UI_UPGRADE_DATA = 'relver/setUIUpgradeData';
|
||||
export const setUIUpgradeData = (upgradeData, version) => {
|
||||
@@ -219,6 +262,6 @@ export const setUIUpgradeData = (upgradeData, version) => {
|
||||
payload: {
|
||||
upgrade_data: upgradeData,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
export const displaySkynetExport = createAction('skynet/displaySkynetExport');
|
||||
export const displaySkynetImport = createAction('skynet/displaySkynetImport');
|
||||
|
||||
@@ -1,71 +1,66 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
|
||||
import {
|
||||
DISPLAY_CONFIRM_YES_NO,
|
||||
NOTIFY_APPLICATION_BUSY,
|
||||
notifyRebootRequired,
|
||||
SET_DISPLAY_SELECT_APPPLATFORM,
|
||||
setAllowMount,
|
||||
setApplicationReady,
|
||||
setLinuxAppPlatform,
|
||||
SET_DISPLAY_SELECT_APPPLATFORM
|
||||
} from '../actions/common_actions';
|
||||
|
||||
export const createCommonReducer = (platformInfo, version) => {
|
||||
return createReducer({
|
||||
AllowMount: false,
|
||||
AppBusy: false,
|
||||
AppBusyTransparent: false,
|
||||
AppPlatform: platformInfo.AppPlatform,
|
||||
AppReady: false,
|
||||
DisplayConfirmYesNo: false,
|
||||
ConfirmTitle: null,
|
||||
DisplaySelectAppPlatform: false,
|
||||
Platform: platformInfo.Platform,
|
||||
RebootRequired: false,
|
||||
Version: version,
|
||||
}, {
|
||||
[DISPLAY_CONFIRM_YES_NO]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplayConfirmYesNo: action.payload.show,
|
||||
ConfirmTitle: action.payload.show ? action.payload.title : null,
|
||||
}
|
||||
return createReducer(
|
||||
{
|
||||
AllowMount: false,
|
||||
AppBusy: false,
|
||||
AppBusyTransparent: false,
|
||||
AppPlatform: platformInfo.AppPlatform,
|
||||
AppReady: false,
|
||||
DisplayConfirmYesNo: false,
|
||||
ConfirmTitle: null,
|
||||
DisplaySelectAppPlatform: false,
|
||||
Platform: platformInfo.Platform,
|
||||
RebootRequired: false,
|
||||
Version: version,
|
||||
},
|
||||
[SET_DISPLAY_SELECT_APPPLATFORM]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplaySelectAppPlatform: action.payload,
|
||||
}
|
||||
},
|
||||
[setAllowMount]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AllowMount: action.payload,
|
||||
}
|
||||
},
|
||||
[setApplicationReady]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AppReady: action.payload,
|
||||
};
|
||||
},
|
||||
[setLinuxAppPlatform]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AppPlatform: action.payload,
|
||||
}
|
||||
},
|
||||
[NOTIFY_APPLICATION_BUSY]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AppBusy: action.payload.busy,
|
||||
AppBusyTransparent: action.payload.busy && action.payload.transparent,
|
||||
};
|
||||
},
|
||||
[notifyRebootRequired]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
RebootRequired: action.payload,
|
||||
};
|
||||
},
|
||||
});
|
||||
{
|
||||
[DISPLAY_CONFIRM_YES_NO]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplayConfirmYesNo: action.payload.show,
|
||||
ConfirmTitle: action.payload.show ? action.payload.title : null,
|
||||
};
|
||||
},
|
||||
[SET_DISPLAY_SELECT_APPPLATFORM]: (state, action) => {
|
||||
return { ...state, DisplaySelectAppPlatform: action.payload };
|
||||
},
|
||||
[setAllowMount]: (state, action) => {
|
||||
return { ...state, AllowMount: action.payload };
|
||||
},
|
||||
[setApplicationReady]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AppReady: action.payload,
|
||||
};
|
||||
},
|
||||
[setLinuxAppPlatform]: (state, action) => {
|
||||
return { ...state, AppPlatform: action.payload };
|
||||
},
|
||||
[NOTIFY_APPLICATION_BUSY]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AppBusy: action.payload.busy,
|
||||
AppBusyTransparent: action.payload.busy && action.payload.transparent,
|
||||
};
|
||||
},
|
||||
[notifyRebootRequired]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
RebootRequired: action.payload,
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
|
||||
import {
|
||||
setAllowDownload,
|
||||
SET_DOWNLOAD_BEGIN,
|
||||
setAllowDownload,
|
||||
setDownloadEnd,
|
||||
setDownloadProgress
|
||||
setDownloadProgress,
|
||||
} from '../actions/download_actions';
|
||||
|
||||
const defaultDownloadState = {
|
||||
@@ -17,37 +18,37 @@ const defaultDownloadState = {
|
||||
DownloadType: null,
|
||||
};
|
||||
|
||||
export const downloadReducer = createReducer({
|
||||
...defaultDownloadState,
|
||||
AllowDownload: false,
|
||||
}, {
|
||||
[setAllowDownload]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AllowDownload: action.payload,
|
||||
};
|
||||
export const downloadReducer = createReducer(
|
||||
{
|
||||
...defaultDownloadState,
|
||||
AllowDownload: false,
|
||||
},
|
||||
[SET_DOWNLOAD_BEGIN]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
...defaultDownloadState,
|
||||
DownloadActive: true,
|
||||
DownloadName: action.payload.name,
|
||||
DownloadType: action.payload.type,
|
||||
DownloadURL: action.payload.url,
|
||||
}
|
||||
},
|
||||
[setDownloadEnd]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
...defaultDownloadState,
|
||||
DownloadResult: action.payload,
|
||||
};
|
||||
},
|
||||
[setDownloadProgress]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DownloadProgress: action.payload,
|
||||
}
|
||||
{
|
||||
[setAllowDownload]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AllowDownload: action.payload,
|
||||
};
|
||||
},
|
||||
[SET_DOWNLOAD_BEGIN]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
...defaultDownloadState,
|
||||
DownloadActive: true,
|
||||
DownloadName: action.payload.name,
|
||||
DownloadType: action.payload.type,
|
||||
DownloadURL: action.payload.url,
|
||||
};
|
||||
},
|
||||
[setDownloadEnd]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
...defaultDownloadState,
|
||||
DownloadResult: action.payload,
|
||||
};
|
||||
},
|
||||
[setDownloadProgress]: (state, action) => {
|
||||
return { ...state, DownloadProgress: action.payload };
|
||||
},
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,52 +1,53 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import {
|
||||
CLEAR_ERROR,
|
||||
CLEAR_INFO,
|
||||
SET_ERROR_INFO,
|
||||
SET_INFO
|
||||
SET_INFO,
|
||||
} from '../actions/error_actions';
|
||||
|
||||
export const errorReducer = createReducer({
|
||||
DisplayError: false,
|
||||
DisplayInfo: false,
|
||||
ErrorCritical: false,
|
||||
ErrorStack: [],
|
||||
InfoStack: [],
|
||||
}, {
|
||||
[CLEAR_ERROR]: state => {
|
||||
const errorStack = (state.ErrorStack.length > 0) ? state.ErrorStack.slice(1) : [];
|
||||
return {
|
||||
...state,
|
||||
DisplayError: (errorStack.length > 0),
|
||||
ErrorStack: errorStack,
|
||||
}
|
||||
export const errorReducer = createReducer(
|
||||
{
|
||||
DisplayError: false,
|
||||
DisplayInfo: false,
|
||||
ErrorCritical: false,
|
||||
ErrorStack: [],
|
||||
InfoStack: [],
|
||||
},
|
||||
[CLEAR_INFO]: state => {
|
||||
const infoStack = (state.InfoStack.length > 0) ? state.InfoStack.slice(1) : [];
|
||||
return {
|
||||
...state,
|
||||
DisplayInfo: (infoStack.length > 0),
|
||||
InfoStack: infoStack,
|
||||
}
|
||||
},
|
||||
[SET_ERROR_INFO]: (state, action) => {
|
||||
const errorStack = [action.payload.msg, ...state.ErrorStack];
|
||||
return {
|
||||
...state,
|
||||
DisplayError: true,
|
||||
ErrorCritical: state.ErrorCritical || action.payload.critical,
|
||||
ErrorStack: errorStack,
|
||||
}
|
||||
},
|
||||
[SET_INFO]: (state, action) => {
|
||||
const infoStack = [{
|
||||
title: action.payload.title,
|
||||
message: action.payload.msg
|
||||
}, ...state.InfoStack];
|
||||
return {
|
||||
...state,
|
||||
DisplayInfo: true,
|
||||
InfoStack: infoStack,
|
||||
}
|
||||
{
|
||||
[CLEAR_ERROR]: (state) => {
|
||||
const errorStack =
|
||||
state.ErrorStack.length > 0 ? state.ErrorStack.slice(1) : [];
|
||||
return {
|
||||
...state,
|
||||
DisplayError: errorStack.length > 0,
|
||||
ErrorStack: errorStack,
|
||||
};
|
||||
},
|
||||
[CLEAR_INFO]: (state) => {
|
||||
const infoStack =
|
||||
state.InfoStack.length > 0 ? state.InfoStack.slice(1) : [];
|
||||
return {
|
||||
...state,
|
||||
DisplayInfo: infoStack.length > 0,
|
||||
InfoStack: infoStack,
|
||||
};
|
||||
},
|
||||
[SET_ERROR_INFO]: (state, action) => {
|
||||
const errorStack = [action.payload.msg, ...state.ErrorStack];
|
||||
return {
|
||||
...state,
|
||||
DisplayError: true,
|
||||
ErrorCritical: state.ErrorCritical || action.payload.critical,
|
||||
ErrorStack: errorStack,
|
||||
};
|
||||
},
|
||||
[SET_INFO]: (state, action) => {
|
||||
const infoStack = [
|
||||
{ title: action.payload.title, message: action.payload.msg },
|
||||
...state.InfoStack,
|
||||
];
|
||||
return { ...state, DisplayInfo: true, InfoStack: infoStack };
|
||||
},
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,60 +1,51 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import {
|
||||
setAutoInstallRelease,
|
||||
setDismissDependencies,
|
||||
setInstallActive,
|
||||
setInstallComplete,
|
||||
setInstallTestActive,
|
||||
setMissingDependencies
|
||||
setMissingDependencies,
|
||||
} from '../actions/install_actions';
|
||||
|
||||
export const installReducer = createReducer({
|
||||
AutoInstallRelease: false,
|
||||
DismissDependencies: false,
|
||||
InstallActive: false,
|
||||
InstallResult: null,
|
||||
InstallTestActive: false,
|
||||
InstallType: null,
|
||||
MissingDependencies: [],
|
||||
}, {
|
||||
[setAutoInstallRelease]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AutoInstallRelease: action.payload,
|
||||
}
|
||||
export const installReducer = createReducer(
|
||||
{
|
||||
AutoInstallRelease: false,
|
||||
DismissDependencies: false,
|
||||
InstallActive: false,
|
||||
InstallResult: null,
|
||||
InstallTestActive: false,
|
||||
InstallType: null,
|
||||
MissingDependencies: [],
|
||||
},
|
||||
[setDismissDependencies]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DismissDependencies: action.payload,
|
||||
}
|
||||
},
|
||||
[setInstallActive]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
InstallActive: true,
|
||||
InstallResult: null,
|
||||
InstallType: action.payload,
|
||||
};
|
||||
},
|
||||
[setInstallComplete]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
InstallActive: false,
|
||||
InstallResult: action.payload,
|
||||
InstallType: null,
|
||||
}
|
||||
},
|
||||
[setInstallTestActive]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
InstallTestActive: action.payload,
|
||||
}
|
||||
},
|
||||
[setMissingDependencies]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
MissingDependencies: action.payload,
|
||||
}
|
||||
{
|
||||
[setAutoInstallRelease]: (state, action) => {
|
||||
return { ...state, AutoInstallRelease: action.payload };
|
||||
},
|
||||
[setDismissDependencies]: (state, action) => {
|
||||
return { ...state, DismissDependencies: action.payload };
|
||||
},
|
||||
[setInstallActive]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
InstallActive: true,
|
||||
InstallResult: null,
|
||||
InstallType: action.payload,
|
||||
};
|
||||
},
|
||||
[setInstallComplete]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
InstallActive: false,
|
||||
InstallResult: action.payload,
|
||||
InstallType: null,
|
||||
};
|
||||
},
|
||||
[setInstallTestActive]: (state, action) => {
|
||||
return { ...state, InstallTestActive: action.payload };
|
||||
},
|
||||
[setMissingDependencies]: (state, action) => {
|
||||
return { ...state, MissingDependencies: action.payload };
|
||||
},
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
|
||||
import * as Constants from '../../constants';
|
||||
import {
|
||||
@@ -12,49 +12,49 @@ import {
|
||||
SET_MOUNT_STATE,
|
||||
SET_MOUNTED,
|
||||
SET_PROVIDER_STATE,
|
||||
setBusy
|
||||
setBusy,
|
||||
} from '../actions/mount_actions';
|
||||
|
||||
export const createMountReducer = state => {
|
||||
export const createMountReducer = (state) => {
|
||||
let providerList = [
|
||||
...Constants.PROVIDER_LIST,
|
||||
...(state.RemoteMounts || []),
|
||||
...(state.S3Mounts || []),
|
||||
];
|
||||
const providerState = providerList
|
||||
.map(provider => {
|
||||
return {
|
||||
[provider]: {
|
||||
AutoMount: false,
|
||||
AutoRestart: false,
|
||||
MountLocation: '',
|
||||
}
|
||||
}
|
||||
})
|
||||
.reduce((map, obj) => {
|
||||
return {...map, ...obj}
|
||||
});
|
||||
|
||||
const mountState = providerList
|
||||
.map(provider => {
|
||||
return {
|
||||
[provider]: {
|
||||
AllowMount: false,
|
||||
DriveLetters: [],
|
||||
Mounted: false,
|
||||
}
|
||||
}
|
||||
})
|
||||
.reduce((map, obj) => {
|
||||
return {...map, ...obj}
|
||||
});
|
||||
|
||||
const autoMountProcessed =
|
||||
providerList.map(provider => {
|
||||
return {[provider]: false,}
|
||||
.map((provider) => {
|
||||
return {
|
||||
[provider]: {
|
||||
AutoMount: false,
|
||||
AutoRestart: false,
|
||||
MountLocation: '',
|
||||
},
|
||||
};
|
||||
})
|
||||
.reduce((map, obj) => {
|
||||
return {...map, ...obj}
|
||||
return { ...map, ...obj };
|
||||
});
|
||||
|
||||
const mountState = providerList
|
||||
.map((provider) => {
|
||||
return {
|
||||
[provider]: {
|
||||
AllowMount: false,
|
||||
DriveLetters: [],
|
||||
Mounted: false,
|
||||
},
|
||||
};
|
||||
})
|
||||
.reduce((map, obj) => {
|
||||
return { ...map, ...obj };
|
||||
});
|
||||
|
||||
const autoMountProcessed = providerList
|
||||
.map((provider) => {
|
||||
return { [provider]: false };
|
||||
})
|
||||
.reduce((map, obj) => {
|
||||
return { ...map, ...obj };
|
||||
});
|
||||
|
||||
return createReducer(
|
||||
@@ -71,52 +71,56 @@ export const createMountReducer = state => {
|
||||
},
|
||||
{
|
||||
[addRemoteMount2]: (state, action) => {
|
||||
let mountState = {...state.MountState};
|
||||
let mountState = { ...state.MountState };
|
||||
mountState[action.payload] = {
|
||||
AllowMount: false,
|
||||
DriveLetters: [],
|
||||
Mounted: false,
|
||||
};
|
||||
|
||||
let providerState = {...state.ProviderState};
|
||||
let providerState = { ...state.ProviderState };
|
||||
providerState[action.payload] = {
|
||||
AutoMount: false,
|
||||
AutoRestart: false,
|
||||
MountLocation: '',
|
||||
};
|
||||
|
||||
let autoMountProcessed = {...state.AutoMountProcessed};
|
||||
let autoMountProcessed = { ...state.AutoMountProcessed };
|
||||
autoMountProcessed[action.payload] = true;
|
||||
|
||||
return {
|
||||
...state, AutoMountProcessed: autoMountProcessed,
|
||||
MountState: mountState, ProviderState: providerState,
|
||||
...state,
|
||||
AutoMountProcessed: autoMountProcessed,
|
||||
MountState: mountState,
|
||||
ProviderState: providerState,
|
||||
RemoteMounts: [...state.RemoteMounts, action.payload],
|
||||
}
|
||||
};
|
||||
},
|
||||
[addS3Mount2]: (state, action) => {
|
||||
let mountState = {...state.MountState};
|
||||
let mountState = { ...state.MountState };
|
||||
mountState[action.payload] = {
|
||||
AllowMount: false,
|
||||
DriveLetters: [],
|
||||
Mounted: false,
|
||||
};
|
||||
|
||||
let providerState = {...state.ProviderState};
|
||||
let providerState = { ...state.ProviderState };
|
||||
providerState[action.payload] = {
|
||||
AutoMount: false,
|
||||
AutoRestart: false,
|
||||
MountLocation: '',
|
||||
};
|
||||
|
||||
let autoMountProcessed = {...state.AutoMountProcessed};
|
||||
let autoMountProcessed = { ...state.AutoMountProcessed };
|
||||
autoMountProcessed[action.payload] = true;
|
||||
|
||||
return {
|
||||
...state, AutoMountProcessed: autoMountProcessed,
|
||||
MountState: mountState, ProviderState: providerState,
|
||||
...state,
|
||||
AutoMountProcessed: autoMountProcessed,
|
||||
MountState: mountState,
|
||||
ProviderState: providerState,
|
||||
S3Mounts: [...state.S3Mounts, action.payload],
|
||||
}
|
||||
};
|
||||
},
|
||||
[DISPLAY_CONFIGURATION]: (state, action) => {
|
||||
return {
|
||||
@@ -127,19 +131,19 @@ export const createMountReducer = state => {
|
||||
};
|
||||
},
|
||||
[removeMount3]: (state, action) => {
|
||||
let mountState = {...state.MountState};
|
||||
let mountState = { ...state.MountState };
|
||||
delete mountState[action.payload];
|
||||
|
||||
let providerState = {...state.ProviderState};
|
||||
let providerState = { ...state.ProviderState };
|
||||
delete providerState[action.payload];
|
||||
|
||||
let autoMountProcessed = {...state.AutoMountProcessed};
|
||||
let autoMountProcessed = { ...state.AutoMountProcessed };
|
||||
delete autoMountProcessed[action.payload];
|
||||
|
||||
const remoteMounts =
|
||||
state.RemoteMounts.filter(i => i !== action.payload);
|
||||
const s3Mounts =
|
||||
state.S3Mounts.filter(i => i !== action.payload);
|
||||
const remoteMounts = state.RemoteMounts.filter(
|
||||
(i) => i !== action.payload
|
||||
);
|
||||
const s3Mounts = state.S3Mounts.filter((i) => i !== action.payload);
|
||||
return {
|
||||
...state,
|
||||
AutoMountProcessed: autoMountProcessed,
|
||||
@@ -150,7 +154,7 @@ export const createMountReducer = state => {
|
||||
};
|
||||
},
|
||||
[RESET_MOUNTS_STATE]: (state, action) => {
|
||||
return {...state, MountsBusy: false, MountState: mountState,}
|
||||
return { ...state, MountsBusy: false, MountState: mountState };
|
||||
},
|
||||
[SET_AUTO_MOUNT_PROCESSED]: (state, action) => {
|
||||
return {
|
||||
@@ -158,7 +162,7 @@ export const createMountReducer = state => {
|
||||
AutoMountProcessed: {
|
||||
...state.AutoMountProcessed,
|
||||
[action.payload.provider]: action.payload.processed,
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
[SET_ALLOW_MOUNT]: (state, action) => {
|
||||
@@ -169,15 +173,13 @@ export const createMountReducer = state => {
|
||||
[action.payload.provider]: {
|
||||
...state.MountState[action.payload.provider],
|
||||
AllowMount: action.payload.allow,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
[setBusy]:
|
||||
(state,
|
||||
action) => {
|
||||
return {...state, MountsBusy: action.payload};
|
||||
},
|
||||
[setBusy]: (state, action) => {
|
||||
return { ...state, MountsBusy: action.payload };
|
||||
},
|
||||
[SET_MOUNT_STATE]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
@@ -185,9 +187,9 @@ export const createMountReducer = state => {
|
||||
...state.MountState,
|
||||
[action.payload.provider]: {
|
||||
...state.MountState[action.payload.provider],
|
||||
...action.payload.state
|
||||
...action.payload.state,
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
[SET_MOUNTED]: (state, action) => {
|
||||
@@ -198,8 +200,8 @@ export const createMountReducer = state => {
|
||||
[action.payload.provider]: {
|
||||
...state.MountState[action.payload.provider],
|
||||
Mounted: action.payload.mounted,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
[SET_PROVIDER_STATE]: (state, action) => {
|
||||
@@ -209,10 +211,11 @@ export const createMountReducer = state => {
|
||||
...state.ProviderState,
|
||||
[action.payload.provider]: {
|
||||
...state.ProviderState[action.payload.provider],
|
||||
...action.payload.state
|
||||
...action.payload.state,
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import {displayPinnedManager} from '../actions/pinned_manager_actions';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { displayPinnedManager } from '../actions/pinned_manager_actions';
|
||||
|
||||
export const pinnedManagerReducer = createReducer({
|
||||
DisplayPinnedManager: false,
|
||||
}, {
|
||||
[displayPinnedManager]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplayPinnedManager: action.payload,
|
||||
};
|
||||
export const pinnedManagerReducer = createReducer(
|
||||
{
|
||||
DisplayPinnedManager: false,
|
||||
},
|
||||
});
|
||||
{
|
||||
[displayPinnedManager]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplayPinnedManager: action.payload,
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import * as Actions from '../actions/release_version_actions';
|
||||
import * as Constants from '../../constants';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
|
||||
const versionLookup = Constants.RELEASE_TYPES.map(k=> {
|
||||
return {
|
||||
[k]: ['unavailable']
|
||||
};
|
||||
import * as Constants from '../../constants';
|
||||
import * as Actions from '../actions/release_version_actions';
|
||||
|
||||
const versionLookup = Constants.RELEASE_TYPES.map((k) => {
|
||||
return { [k]: ['unavailable'] };
|
||||
}).reduce((map, obj) => {
|
||||
return {
|
||||
...map,
|
||||
@@ -13,95 +12,95 @@ const versionLookup = Constants.RELEASE_TYPES.map(k=> {
|
||||
};
|
||||
});
|
||||
|
||||
export const releaseVersionReducer = createReducer({
|
||||
AllowDismissDependencies: false,
|
||||
DismissNewReleasesAvailable: true,
|
||||
InstalledVersion: 'none',
|
||||
LocationsLookup: {},
|
||||
NewReleasesAvailable: [],
|
||||
NewReleasesAvailable2: [],
|
||||
Release: Constants.DEFAULT_RELEASE,
|
||||
ReleaseUpgradeAvailable: false,
|
||||
UpgradeAvailable: false,
|
||||
UpgradeData: null,
|
||||
UpgradeVersion: null,
|
||||
UpgradeDismissed: false,
|
||||
Version: -1,
|
||||
VersionLookup: versionLookup,
|
||||
}, {
|
||||
[Actions.CLEAR_UI_UPGRADE]: state => {
|
||||
return {
|
||||
...state,
|
||||
UpgradeAvailable: false,
|
||||
UpgradeDismissed: false,
|
||||
UpgradeData: null,
|
||||
UpgradeVersion: null,
|
||||
};
|
||||
export const releaseVersionReducer = createReducer(
|
||||
{
|
||||
AllowDismissDependencies: false,
|
||||
DismissNewReleasesAvailable: true,
|
||||
InstalledVersion: 'none',
|
||||
LocationsLookup: {},
|
||||
NewReleasesAvailable: [],
|
||||
NewReleasesAvailable2: [],
|
||||
Release: Constants.DEFAULT_RELEASE,
|
||||
ReleaseUpgradeAvailable: false,
|
||||
UpgradeAvailable: false,
|
||||
UpgradeData: null,
|
||||
UpgradeVersion: null,
|
||||
UpgradeDismissed: false,
|
||||
Version: -1,
|
||||
VersionLookup: versionLookup,
|
||||
},
|
||||
[Actions.NOTIFY_ACTIVE_RELEASE]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
Release: action.payload.release,
|
||||
Version: action.payload.version
|
||||
};
|
||||
},
|
||||
[Actions.setAllowDismissDependencies]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AllowDismissDependencies: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setDismissNewReleasesAvailable]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DismissNewReleasesAvailable: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setDismissUIUpgrade]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
UpgradeDismissed: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setInstalledVersion]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
InstalledVersion: action.payload,
|
||||
}
|
||||
},
|
||||
[Actions.setNewReleasesAvailable]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DismissNewReleasesAvailable: false,
|
||||
NewReleasesAvailable: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setNewReleasesAvailable2]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
NewReleasesAvailable2: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.SET_RELEASE_DATA]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
LocationsLookup: action.payload.locations,
|
||||
VersionLookup: action.payload.versions,
|
||||
};
|
||||
},
|
||||
[Actions.setReleaseUpgradeAvailable]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
ReleaseUpgradeAvailable: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.SET_UI_UPGRADE_DATA]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
UpgradeAvailable: true,
|
||||
UpgradeData: action.payload.upgrade_data,
|
||||
UpgradeVersion: action.payload.version,
|
||||
UpgradeDismissed: false,
|
||||
};
|
||||
{
|
||||
[Actions.CLEAR_UI_UPGRADE]: (state) => {
|
||||
return {
|
||||
...state,
|
||||
UpgradeAvailable: false,
|
||||
UpgradeDismissed: false,
|
||||
UpgradeData: null,
|
||||
UpgradeVersion: null,
|
||||
};
|
||||
},
|
||||
[Actions.NOTIFY_ACTIVE_RELEASE]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
Release: action.payload.release,
|
||||
Version: action.payload.version,
|
||||
};
|
||||
},
|
||||
[Actions.setAllowDismissDependencies]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AllowDismissDependencies: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setDismissNewReleasesAvailable]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DismissNewReleasesAvailable: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setDismissUIUpgrade]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
UpgradeDismissed: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setInstalledVersion]: (state, action) => {
|
||||
return { ...state, InstalledVersion: action.payload };
|
||||
},
|
||||
[Actions.setNewReleasesAvailable]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DismissNewReleasesAvailable: false,
|
||||
NewReleasesAvailable: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.setNewReleasesAvailable2]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
NewReleasesAvailable2: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.SET_RELEASE_DATA]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
LocationsLookup: action.payload.locations,
|
||||
VersionLookup: action.payload.versions,
|
||||
};
|
||||
},
|
||||
[Actions.setReleaseUpgradeAvailable]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
ReleaseUpgradeAvailable: action.payload,
|
||||
};
|
||||
},
|
||||
[Actions.SET_UI_UPGRADE_DATA]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
UpgradeAvailable: true,
|
||||
UpgradeData: action.payload.upgrade_data,
|
||||
UpgradeVersion: action.payload.version,
|
||||
UpgradeDismissed: false,
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import {createReducer} from '@reduxjs/toolkit';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import * as Actions from '../actions/skynet_actions';
|
||||
|
||||
export const skynetReducer = createReducer({
|
||||
DisplayExport: false,
|
||||
DisplayImport: false,
|
||||
}, {
|
||||
[Actions.displaySkynetExport]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplayExport: action.payload,
|
||||
}
|
||||
export const skynetReducer = createReducer(
|
||||
{
|
||||
DisplayExport: false,
|
||||
DisplayImport: false,
|
||||
},
|
||||
[Actions.displaySkynetImport]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplayImport: action.payload,
|
||||
}
|
||||
},
|
||||
});
|
||||
{
|
||||
[Actions.displaySkynetExport]: (state, action) => {
|
||||
return { ...state, DisplayExport: action.payload };
|
||||
},
|
||||
[Actions.displaySkynetImport]: (state, action) => {
|
||||
return { ...state, DisplayImport: action.payload };
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import {configureStore, getDefaultMiddleware} from '@reduxjs/toolkit';
|
||||
import {createCommonReducer} from '../reducers/common_reducer';
|
||||
import {downloadReducer} from '../reducers/download_reducer';
|
||||
import {errorReducer} from '../reducers/error_reducer';
|
||||
import {installReducer} from '../reducers/install_reducer';
|
||||
import {createMountReducer} from '../reducers/mount_reducer';
|
||||
import {releaseVersionReducer} from '../reducers/release_version_reducer';
|
||||
import {skynetReducer} from '../reducers/skynet_reducer';
|
||||
import {pinnedManagerReducer} from '../reducers/pinned_manager_reducer'
|
||||
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
|
||||
|
||||
import { createCommonReducer } from '../reducers/common_reducer';
|
||||
import { downloadReducer } from '../reducers/download_reducer';
|
||||
import { errorReducer } from '../reducers/error_reducer';
|
||||
import { installReducer } from '../reducers/install_reducer';
|
||||
import { createMountReducer } from '../reducers/mount_reducer';
|
||||
import { pinnedManagerReducer } from '../reducers/pinned_manager_reducer';
|
||||
import { releaseVersionReducer } from '../reducers/release_version_reducer';
|
||||
import { skynetReducer } from '../reducers/skynet_reducer';
|
||||
|
||||
export default function createAppStore(platformInfo, version, state) {
|
||||
const reducer = {
|
||||
@@ -25,6 +26,6 @@ export default function createAppStore(platformInfo, version, state) {
|
||||
return configureStore({
|
||||
reducer,
|
||||
middleware,
|
||||
devTools: process.env.NODE_ENV !== 'production'
|
||||
devTools: process.env.NODE_ENV !== 'production',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const Constants = require('../../constants');
|
||||
|
||||
const addListeners = (ipcMain, {closeApplication, setWindowVisibility}) => {
|
||||
const addListeners = (ipcMain, { closeApplication, setWindowVisibility }) => {
|
||||
ipcMain.on(Constants.IPC_Shutdown, () => {
|
||||
closeApplication();
|
||||
});
|
||||
@@ -9,12 +9,10 @@ const addListeners = (ipcMain, {closeApplication, setWindowVisibility}) => {
|
||||
setWindowVisibility(true);
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Show_Window + '_sync', event => {
|
||||
ipcMain.on(Constants.IPC_Show_Window + '_sync', (event) => {
|
||||
setWindowVisibility(true);
|
||||
event.returnValue = true;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -1,48 +1,70 @@
|
||||
const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
const addListeners = (ipcMain, { standardIPCReply }) => {
|
||||
ipcMain.on(Constants.IPC_Get_Config, (event, data) => {
|
||||
helpers
|
||||
.getConfig(data.Version, data.Provider, data.Remote, data.S3)
|
||||
.then((data) => {
|
||||
if (data.Code === 0) {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {
|
||||
Config: data.Data,
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, data.Code);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, error);
|
||||
});
|
||||
.getConfig(data.Version, data.Provider, data.Remote, data.S3)
|
||||
.then((data) => {
|
||||
if (data.Code === 0) {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {
|
||||
Config: data.Data,
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Get_Config_Reply,
|
||||
{},
|
||||
data.Code
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Get_Config_Template, (event, data) => {
|
||||
helpers
|
||||
.getConfigTemplate(data.Version, data.Provider, data.Remote, data.S3)
|
||||
.then((data) => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {
|
||||
Template: data,
|
||||
.getConfigTemplate(data.Version, data.Provider, data.Remote, data.S3)
|
||||
.then((data) => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {
|
||||
Template: data,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Get_Config_Template_Reply,
|
||||
{},
|
||||
error
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Set_Config_Values, (event, data) => {
|
||||
const setConfigValue = (i) => {
|
||||
if (i < data.Items.length) {
|
||||
helpers
|
||||
.setConfigValue(data.Items[i].Name, data.Items[i].Value, data.Provider, data.Remote, data.S3, data.Version)
|
||||
.then(() => {
|
||||
setConfigValue(++i);
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Set_Config_Values_Reply, {}, error);
|
||||
});
|
||||
.setConfigValue(
|
||||
data.Items[i].Name,
|
||||
data.Items[i].Value,
|
||||
data.Provider,
|
||||
data.Remote,
|
||||
data.S3,
|
||||
data.Version
|
||||
)
|
||||
.then(() => {
|
||||
setConfigValue(++i);
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Set_Config_Values_Reply,
|
||||
{},
|
||||
error
|
||||
);
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Set_Config_Values_Reply, {});
|
||||
}
|
||||
@@ -51,6 +73,4 @@ const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
const addListeners = (ipcMain, { standardIPCReply }) => {
|
||||
ipcMain.on(Constants.IPC_Check_Daemon_Version, (event, data) => {
|
||||
helpers
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then(code => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||
Valid: (code === 0),
|
||||
Code: code,
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then((code) => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||
Valid: code === 0,
|
||||
Code: code,
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Check_Daemon_Version_Reply,
|
||||
{
|
||||
Valid: false,
|
||||
},
|
||||
e
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||
Valid: false,
|
||||
}, e);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Daemon_Version + '_sync', (event, data) => {
|
||||
helpers
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then(code => {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Success: true,
|
||||
Valid: (code === 0),
|
||||
Code: code,
|
||||
},
|
||||
};
|
||||
})
|
||||
.catch(e => {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Error: e.toString(),
|
||||
Success: false,
|
||||
Valid: false
|
||||
},
|
||||
};
|
||||
});
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then((code) => {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Success: true,
|
||||
Valid: code === 0,
|
||||
Code: code,
|
||||
},
|
||||
};
|
||||
})
|
||||
.catch((e) => {
|
||||
event.returnValue = {
|
||||
data: { Error: e.toString(), Success: false, Valid: false },
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -2,7 +2,7 @@ const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
const addListeners = (ipcMain, { standardIPCReply }) => {
|
||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed, (event, data) => {
|
||||
try {
|
||||
const exists = fs.lstatSync(data.File).isFile();
|
||||
@@ -13,83 +13,99 @@ const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
});
|
||||
} catch (e) {
|
||||
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
||||
data : {
|
||||
data: {
|
||||
Exists: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed + '_sync', (event, data) => {
|
||||
try {
|
||||
const ls = fs.lstatSync(data.File);
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Exists: ls.isFile() || ls.isSymbolicLink(),
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Exists: false
|
||||
},
|
||||
};
|
||||
ipcMain.on(
|
||||
Constants.IPC_Check_Dependency_Installed + '_sync',
|
||||
(event, data) => {
|
||||
try {
|
||||
const ls = fs.lstatSync(data.File);
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Exists: ls.isFile() || ls.isSymbolicLink(),
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
event.returnValue = {
|
||||
data: { Exists: false },
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
ipcMain.on(Constants.IPC_Install_Dependency, (event, data) => {
|
||||
if (data.Source.toLowerCase().endsWith('.dmg')) {
|
||||
helpers
|
||||
.executeAsync('open', ['-a', 'Finder', '-W', data.Source])
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
})
|
||||
.catch(error=> {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
} else {
|
||||
const execInstall = () => {
|
||||
helpers
|
||||
.executeAndWait(data.Source)
|
||||
.executeAsync('open', ['-a', 'Finder', '-W', data.Source])
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Install_Dependency_Reply,
|
||||
{
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
},
|
||||
error
|
||||
);
|
||||
});
|
||||
};
|
||||
if (data.IsWinFSP) {
|
||||
} else {
|
||||
const execInstall = () => {
|
||||
helpers
|
||||
.performWindowsUninstall(Constants.WINFSP_VERSION_NAMES)
|
||||
.then(uninstalled => {
|
||||
if (uninstalled) {
|
||||
.executeAndWait(data.Source)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
RebootRequired: true,
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
} else {
|
||||
execInstall();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Install_Dependency_Reply,
|
||||
{
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
},
|
||||
error
|
||||
);
|
||||
});
|
||||
};
|
||||
if (data.IsWinFSP) {
|
||||
helpers
|
||||
.performWindowsUninstall(Constants.WINFSP_VERSION_NAMES)
|
||||
.then((uninstalled) => {
|
||||
if (uninstalled) {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
RebootRequired: true,
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
} else {
|
||||
execInstall();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Install_Dependency_Reply,
|
||||
{
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
},
|
||||
error
|
||||
);
|
||||
});
|
||||
} else {
|
||||
execInstall();
|
||||
}
|
||||
@@ -97,6 +113,4 @@ const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -2,24 +2,32 @@ const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
const path = require('path');
|
||||
|
||||
const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
const addListeners = (ipcMain, { standardIPCReply }) => {
|
||||
ipcMain.on(Constants.IPC_Download_File, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Filename);
|
||||
helpers.downloadFile(data.URL, destination, (progress) => {
|
||||
standardIPCReply(event, Constants.IPC_Download_File_Progress, {
|
||||
Destination: destination,
|
||||
Progress: progress,
|
||||
URL: data.URL,
|
||||
});
|
||||
}, error => {
|
||||
standardIPCReply(event, Constants.IPC_Download_File_Complete, {
|
||||
Destination: destination,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
helpers.downloadFile(
|
||||
data.URL,
|
||||
destination,
|
||||
(progress) => {
|
||||
standardIPCReply(event, Constants.IPC_Download_File_Progress, {
|
||||
Destination: destination,
|
||||
Progress: progress,
|
||||
URL: data.URL,
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Download_File_Complete,
|
||||
{
|
||||
Destination: destination,
|
||||
URL: data.URL,
|
||||
},
|
||||
error
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
|
||||
const addListeners = (ipcMain, {getMainWindow, dialog}) => {
|
||||
const addListeners = (ipcMain, { getMainWindow, dialog }) => {
|
||||
ipcMain.on(Constants.IPC_Browse_Directory + '_sync', (event, data) => {
|
||||
dialog.showOpenDialog(getMainWindow(), {
|
||||
defaultPath: data.Location,
|
||||
properties: ['openDirectory'],
|
||||
title: data.Title,
|
||||
}, (filePaths) => {
|
||||
if (filePaths && (filePaths.length > 0)) {
|
||||
event.returnValue = filePaths[0];
|
||||
} else {
|
||||
event.returnValue = '';
|
||||
dialog.showOpenDialog(
|
||||
getMainWindow(),
|
||||
{
|
||||
defaultPath: data.Location,
|
||||
properties: ['openDirectory'],
|
||||
title: data.Title,
|
||||
},
|
||||
(filePaths) => {
|
||||
if (filePaths && filePaths.length > 0) {
|
||||
event.returnValue = filePaths[0];
|
||||
} else {
|
||||
event.returnValue = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Delete_File, (event, data) => {
|
||||
@@ -21,11 +25,8 @@ const addListeners = (ipcMain, {getMainWindow, dialog}) => {
|
||||
if (fs.existsSync(data.FilePath)) {
|
||||
fs.unlinkSync(data.FilePath);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -10,38 +10,45 @@ let manualMountDetection = {};
|
||||
let mountedData = {};
|
||||
let mountedLocations = [];
|
||||
|
||||
const clearManualMountDetection = provider => {
|
||||
const clearManualMountDetection = (provider) => {
|
||||
if (manualMountDetection[provider]) {
|
||||
clearInterval(manualMountDetection[provider]);
|
||||
delete manualMountDetection[provider];
|
||||
}
|
||||
};
|
||||
|
||||
const monitorMount = (sender, provider, providerList, version, pid, location) => {
|
||||
const monitorMount = (
|
||||
sender,
|
||||
provider,
|
||||
providerList,
|
||||
version,
|
||||
pid,
|
||||
location
|
||||
) => {
|
||||
manualMountDetection[provider] = setInterval(() => {
|
||||
helpers
|
||||
.detectRepertoryMounts(version, providerList)
|
||||
.then(result => {
|
||||
if (result[provider].PID !== pid) {
|
||||
if (result[provider].PID === -1) {
|
||||
clearManualMountDetection(provider);
|
||||
sender.send(Constants.IPC_Unmount_Drive_Reply, {
|
||||
data: {
|
||||
Expected: expectedUnmount[provider],
|
||||
Location: location,
|
||||
Provider: provider,
|
||||
Error: Error(provider + ' Unmounted').toString(),
|
||||
Success: false,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pid = result[provider].PID;
|
||||
.detectRepertoryMounts(version, providerList)
|
||||
.then((result) => {
|
||||
if (result[provider].PID !== pid) {
|
||||
if (result[provider].PID === -1) {
|
||||
clearManualMountDetection(provider);
|
||||
sender.send(Constants.IPC_Unmount_Drive_Reply, {
|
||||
data: {
|
||||
Expected: expectedUnmount[provider],
|
||||
Location: location,
|
||||
Provider: provider,
|
||||
Error: Error(provider + ' Unmounted').toString(),
|
||||
Success: false,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
pid = result[provider].PID;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}, 6000);
|
||||
};
|
||||
|
||||
@@ -55,22 +62,27 @@ const unmountAllDrives = () => {
|
||||
// Unmount all items
|
||||
for (const mountLocation of mountedLocations) {
|
||||
const data = mountedData[mountLocation];
|
||||
helpers.stopMountProcessSync(data.Version, data.Provider, data.Remote, data.S3);
|
||||
helpers.stopMountProcessSync(
|
||||
data.Version,
|
||||
data.Provider,
|
||||
data.Remote,
|
||||
data.S3
|
||||
);
|
||||
}
|
||||
|
||||
mountedLocations = [];
|
||||
mountedData = {};
|
||||
};
|
||||
|
||||
const addListeners = (ipcMain, {setTrayImage, standardIPCReply}) => {
|
||||
const addListeners = (ipcMain, { setTrayImage, standardIPCReply }) => {
|
||||
ipcMain.on(Constants.IPC_Check_Mount_Location + '_sync', (event, data) => {
|
||||
let response = {
|
||||
Success: true,
|
||||
Error: ''
|
||||
};
|
||||
let response = { Success: true, Error: '' };
|
||||
|
||||
try {
|
||||
if (fs.existsSync(data.Location) && fs.statSync(data.Location).isDirectory()) {
|
||||
if (
|
||||
fs.existsSync(data.Location) &&
|
||||
fs.statSync(data.Location).isDirectory()
|
||||
) {
|
||||
if (fs.readdirSync(data.Location).length !== 0) {
|
||||
response.Success = false;
|
||||
response.Error = 'Directory not empty: ' + data.Location;
|
||||
@@ -106,8 +118,7 @@ const addListeners = (ipcMain, {setTrayImage, standardIPCReply}) => {
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of providerList) {
|
||||
driveInUse = locations[provider].startsWith(drive);
|
||||
if (driveInUse)
|
||||
break;
|
||||
if (driveInUse) break;
|
||||
}
|
||||
}
|
||||
if (!driveInUse) {
|
||||
@@ -117,17 +128,18 @@ const addListeners = (ipcMain, {setTrayImage, standardIPCReply}) => {
|
||||
driveLetters[provider].push(drive);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of providerList) {
|
||||
if (locations[provider].length > 0) {
|
||||
if (!driveLetters[provider].find((driveLetter) => {
|
||||
return driveLetter === locations[provider];
|
||||
})) {
|
||||
if (
|
||||
!driveLetters[provider].find((driveLetter) => {
|
||||
return driveLetter === locations[provider];
|
||||
})
|
||||
) {
|
||||
driveLetters[provider].push(locations[provider]);
|
||||
}
|
||||
}
|
||||
@@ -135,66 +147,79 @@ const addListeners = (ipcMain, {setTrayImage, standardIPCReply}) => {
|
||||
}
|
||||
};
|
||||
|
||||
const setImage = locations => {
|
||||
const setImage = (locations) => {
|
||||
let driveInUse;
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of providerList) {
|
||||
driveInUse = locations[provider] && locations[provider].length > 0;
|
||||
if (driveInUse)
|
||||
break;
|
||||
if (driveInUse) break;
|
||||
}
|
||||
}
|
||||
|
||||
setTrayImage(driveInUse)
|
||||
setTrayImage(driveInUse);
|
||||
};
|
||||
|
||||
helpers
|
||||
.detectRepertoryMounts(data.Version, providerList)
|
||||
.then((results) => {
|
||||
let storageData = {};
|
||||
let locations = {};
|
||||
for (const provider of providerList) {
|
||||
storageData[provider] = results[provider] ? results[provider] : {
|
||||
Active: false,
|
||||
Location: '',
|
||||
PID: -1,
|
||||
};
|
||||
locations[provider] = storageData[provider].Location;
|
||||
.detectRepertoryMounts(data.Version, providerList)
|
||||
.then((results) => {
|
||||
let storageData = {};
|
||||
let locations = {};
|
||||
for (const provider of providerList) {
|
||||
storageData[provider] = results[provider]
|
||||
? results[provider]
|
||||
: {
|
||||
Active: false,
|
||||
Location: '',
|
||||
PID: -1,
|
||||
};
|
||||
locations[provider] = storageData[provider].Location;
|
||||
|
||||
if (storageData[provider].PID !== -1) {
|
||||
expectedUnmount[provider] = false;
|
||||
if (firstMountCheck) {
|
||||
monitorMount(event.sender, provider, providerList, data.Version, storageData[provider].PID, storageData[provider].Location);
|
||||
if (storageData[provider].PID !== -1) {
|
||||
expectedUnmount[provider] = false;
|
||||
if (firstMountCheck) {
|
||||
monitorMount(
|
||||
event.sender,
|
||||
provider,
|
||||
providerList,
|
||||
data.Version,
|
||||
storageData[provider].PID,
|
||||
storageData[provider].Location
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters(locations);
|
||||
}
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters(locations);
|
||||
}
|
||||
|
||||
setImage(locations);
|
||||
if (firstMountCheck) {
|
||||
firstMountCheck = false;
|
||||
}
|
||||
standardIPCReply(event, Constants.IPC_Detect_Mount_Reply, {
|
||||
Active: storageData[provider].Active,
|
||||
DriveLetters: driveLetters[provider],
|
||||
Location: locations[provider],
|
||||
PID: storageData[provider].PID,
|
||||
Provider: provider,
|
||||
setImage(locations);
|
||||
if (firstMountCheck) {
|
||||
firstMountCheck = false;
|
||||
}
|
||||
standardIPCReply(event, Constants.IPC_Detect_Mount_Reply, {
|
||||
Active: storageData[provider].Active,
|
||||
DriveLetters: driveLetters[provider],
|
||||
Location: locations[provider],
|
||||
PID: storageData[provider].PID,
|
||||
Provider: provider,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters({});
|
||||
}
|
||||
setImage({});
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Detect_Mount_Reply,
|
||||
{
|
||||
DriveLetters: driveLetters[provider],
|
||||
Provider: provider,
|
||||
},
|
||||
error
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters({});
|
||||
}
|
||||
setImage({});
|
||||
standardIPCReply(event, Constants.IPC_Detect_Mount_Reply, {
|
||||
DriveLetters: driveLetters[provider],
|
||||
Provider: provider,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Mount_Drive, (event, data) => {
|
||||
@@ -216,28 +241,40 @@ const addListeners = (ipcMain, {setTrayImage, standardIPCReply}) => {
|
||||
delete mountedData[data.Location];
|
||||
}
|
||||
|
||||
standardIPCReply(event, Constants.IPC_Unmount_Drive_Reply, {
|
||||
Expected: expectedUnmount[data.Provider],
|
||||
Location: data.Location,
|
||||
Provider: data.Provider,
|
||||
Remote: data.Remote,
|
||||
S3: data.S3,
|
||||
}, error || Error(data.Provider + ' Unmounted'));
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Unmount_Drive_Reply,
|
||||
{
|
||||
Expected: expectedUnmount[data.Provider],
|
||||
Location: data.Location,
|
||||
Provider: data.Provider,
|
||||
Remote: data.Remote,
|
||||
S3: data.S3,
|
||||
},
|
||||
error || Error(data.Provider + ' Unmounted')
|
||||
);
|
||||
};
|
||||
helpers
|
||||
.executeMount(data.Version, data.Provider, data.Remote, data.S3, data.Location, (error, pid) => {
|
||||
errorHandler(pid, error);
|
||||
})
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Mount_Drive_Reply, {
|
||||
Provider: data.Provider,
|
||||
Remote: data.Remote,
|
||||
S3: data.S3,
|
||||
.executeMount(
|
||||
data.Version,
|
||||
data.Provider,
|
||||
data.Remote,
|
||||
data.S3,
|
||||
data.Location,
|
||||
(error, pid) => {
|
||||
errorHandler(pid, error);
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Mount_Drive_Reply, {
|
||||
Provider: data.Provider,
|
||||
Remote: data.Remote,
|
||||
S3: data.S3,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
errorHandler(-1, error);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
errorHandler(-1, error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -245,17 +282,31 @@ const addListeners = (ipcMain, {setTrayImage, standardIPCReply}) => {
|
||||
if (data.Remote) {
|
||||
data.Name = data.Name.replace(':', '_');
|
||||
}
|
||||
const dataDirectory = path.resolve(path.join(helpers.getDataDirectory(), '..', data.Remote ? 'remote' : 's3', data.Name));
|
||||
const dataDirectory = path.resolve(
|
||||
path.join(
|
||||
helpers.getDataDirectory(),
|
||||
'..',
|
||||
data.Remote ? 'remote' : 's3',
|
||||
data.Name
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
helpers.removeDirectoryRecursively(dataDirectory);
|
||||
standardIPCReply(event, Constants.IPC_Remove_Mount_Reply, {DataDirectory: dataDirectory});
|
||||
standardIPCReply(event, Constants.IPC_Remove_Mount_Reply, {
|
||||
DataDirectory: dataDirectory,
|
||||
});
|
||||
} catch (e) {
|
||||
standardIPCReply(event, Constants.IPC_Remove_Mount_Reply, {DataDirectory: dataDirectory}, e);
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Remove_Mount_Reply,
|
||||
{ DataDirectory: dataDirectory },
|
||||
e
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Unmount_All_Drives, event => {
|
||||
ipcMain.on(Constants.IPC_Unmount_All_Drives, (event) => {
|
||||
unmountAllDrives();
|
||||
standardIPCReply(event, Constants.IPC_Unmount_All_Drives_Reply);
|
||||
});
|
||||
@@ -265,17 +316,17 @@ const addListeners = (ipcMain, {setTrayImage, standardIPCReply}) => {
|
||||
|
||||
expectedUnmount[data.Provider] = true;
|
||||
helpers
|
||||
.stopMountProcess(data.Version, data.Provider, data.Remote, data.S3)
|
||||
.then(result => {
|
||||
console.log(result);
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
.stopMountProcess(data.Version, data.Provider, data.Remote, data.S3)
|
||||
.then((result) => {
|
||||
console.log(result);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners,
|
||||
unmountAllDrives
|
||||
unmountAllDrives,
|
||||
};
|
||||
|
||||
@@ -1,49 +1,64 @@
|
||||
const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
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,
|
||||
.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);
|
||||
});
|
||||
})
|
||||
.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,
|
||||
.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);
|
||||
});
|
||||
})
|
||||
.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_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;
|
||||
});
|
||||
.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
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -10,11 +10,11 @@ const getPlatformOverride = () => {
|
||||
return _platformOverride;
|
||||
};
|
||||
|
||||
const setPlatformOverride = platformOverride => {
|
||||
const setPlatformOverride = (platformOverride) => {
|
||||
_platformOverride = platformOverride;
|
||||
};
|
||||
|
||||
const addListeners = (ipcMain, {detectScript, saveUiSettings}) => {
|
||||
const addListeners = (ipcMain, { detectScript, saveUiSettings }) => {
|
||||
ipcMain.on(Constants.IPC_Get_Platform, (event) => {
|
||||
const sendResponse = (appPlatform, platform) => {
|
||||
event.sender.send(Constants.IPC_Get_Platform_Reply, {
|
||||
@@ -25,40 +25,44 @@ const addListeners = (ipcMain, {detectScript, saveUiSettings}) => {
|
||||
|
||||
const platform = os.platform();
|
||||
if (platform === 'linux') {
|
||||
if (_platformOverride && (_platformOverride.length > 0)) {
|
||||
if (_platformOverride && _platformOverride.length > 0) {
|
||||
sendResponse(_platformOverride, 'linux');
|
||||
} else {
|
||||
const scriptFile = path.join(os.tmpdir(), 'repertory_detect_linux.sh');
|
||||
fs.writeFileSync(scriptFile, detectScript);
|
||||
|
||||
helpers
|
||||
.executeScript(scriptFile)
|
||||
.then(data => {
|
||||
let appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
||||
if (appPlatform === 'unknown') {
|
||||
helpers
|
||||
.downloadFile(Constants.LINUX_DETECT_SCRIPT_URL, scriptFile, null, err => {
|
||||
if (err) {
|
||||
sendResponse(appPlatform, platform);
|
||||
} else {
|
||||
helpers
|
||||
.executeScript(scriptFile)
|
||||
.then(data => {
|
||||
appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
||||
sendResponse(appPlatform, platform);
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(appPlatform, platform);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sendResponse(appPlatform, platform);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(platform, platform);
|
||||
});
|
||||
.executeScript(scriptFile)
|
||||
.then((data) => {
|
||||
let appPlatform = data.replace(/(\r\n|\n|\r)/gm, '');
|
||||
if (appPlatform === 'unknown') {
|
||||
helpers.downloadFile(
|
||||
Constants.LINUX_DETECT_SCRIPT_URL,
|
||||
scriptFile,
|
||||
null,
|
||||
(err) => {
|
||||
if (err) {
|
||||
sendResponse(appPlatform, platform);
|
||||
} else {
|
||||
helpers
|
||||
.executeScript(scriptFile)
|
||||
.then((data) => {
|
||||
appPlatform = data.replace(/(\r\n|\n|\r)/gm, '');
|
||||
sendResponse(appPlatform, platform);
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(appPlatform, platform);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
sendResponse(appPlatform, platform);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(platform, platform);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
sendResponse(platform, platform);
|
||||
@@ -75,5 +79,5 @@ const addListeners = (ipcMain, {detectScript, saveUiSettings}) => {
|
||||
module.exports = {
|
||||
getPlatformOverride,
|
||||
setPlatformOverride,
|
||||
addListeners
|
||||
addListeners,
|
||||
};
|
||||
|
||||
@@ -5,28 +5,35 @@ const os = require('os');
|
||||
const path = require('path');
|
||||
const unzip = require('unzipper');
|
||||
|
||||
const addListeners = (ipcMain, {getCleanupReleases, standardIPCReply}) => {
|
||||
const addListeners = (ipcMain, { getCleanupReleases, standardIPCReply }) => {
|
||||
ipcMain.on(Constants.IPC_Check_Installed, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
||||
helpers
|
||||
.getMissingDependencies(data.Dependencies)
|
||||
.then((dependencies) => {
|
||||
let exists = false;
|
||||
try {
|
||||
exists = fs.existsSync(destination) && fs.lstatSync(destination).isDirectory();
|
||||
} catch (e) {
|
||||
}
|
||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||
Dependencies: dependencies,
|
||||
Exists: exists,
|
||||
Version: data.Version,
|
||||
.getMissingDependencies(data.Dependencies)
|
||||
.then((dependencies) => {
|
||||
let exists = false;
|
||||
try {
|
||||
exists =
|
||||
fs.existsSync(destination) &&
|
||||
fs.lstatSync(destination).isDirectory();
|
||||
} catch (e) {}
|
||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||
Dependencies: dependencies,
|
||||
Exists: exists,
|
||||
Version: data.Version,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Check_Installed_Reply,
|
||||
{
|
||||
Dependencies: [],
|
||||
Version: data.Version,
|
||||
},
|
||||
error
|
||||
);
|
||||
});
|
||||
}).catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||
Dependencies: [],
|
||||
Version: data.Version,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Cleanup_Releases + '_sync', (event, data) => {
|
||||
@@ -44,52 +51,61 @@ const addListeners = (ipcMain, {getCleanupReleases, standardIPCReply}) => {
|
||||
|
||||
const stream = fs.createReadStream(data.Source);
|
||||
stream
|
||||
.pipe(unzip.Extract({ path: destination }))
|
||||
.on('error', error => {
|
||||
try {
|
||||
helpers.removeDirectoryRecursively(destination);
|
||||
} catch (e) {
|
||||
}
|
||||
stream.close();
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
}, error);
|
||||
})
|
||||
.on('finish', () => {
|
||||
stream.close();
|
||||
if (os.platform() !== 'win32') {
|
||||
helpers
|
||||
.executeAndWait("chmod +x \"" + path.join(destination, 'repertory') + "\"")
|
||||
.then(() => {
|
||||
.pipe(unzip.Extract({ path: destination }))
|
||||
.on('error', (error) => {
|
||||
try {
|
||||
helpers.removeDirectoryRecursively(destination);
|
||||
} catch (e) {}
|
||||
stream.close();
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Extract_Release_Complete,
|
||||
{
|
||||
Source: data.Source,
|
||||
},
|
||||
error
|
||||
);
|
||||
})
|
||||
.on('finish', () => {
|
||||
stream.close();
|
||||
if (os.platform() !== 'win32') {
|
||||
helpers
|
||||
.executeAndWait(
|
||||
'chmod +x "' + path.join(destination, 'repertory') + '"'
|
||||
)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Extract_Release_Complete,
|
||||
{
|
||||
Source: data.Source,
|
||||
},
|
||||
error
|
||||
);
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
}, error);
|
||||
})
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Test_Release, (event, data) => {
|
||||
helpers
|
||||
.testRepertoryBinary(data.Version)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {}, error);
|
||||
});
|
||||
.testRepertoryBinary(data.Version)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {});
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -1,47 +1,50 @@
|
||||
const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, {standardIPCReply}) => {
|
||||
const addListeners = (ipcMain, { standardIPCReply }) => {
|
||||
ipcMain.on(Constants.IPC_Export_Skylinks, (event, data) => {
|
||||
helpers
|
||||
.exportSkylinks(data.Version, data.Paths)
|
||||
.then(result => {
|
||||
standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {
|
||||
Result: result,
|
||||
.exportSkylinks(data.Version, data.Paths)
|
||||
.then((result) => {
|
||||
standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {
|
||||
Result: result,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {}, error);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Grab_Skynet_Tree, (event, data) => {
|
||||
helpers
|
||||
.grabSkynetFileTree(data.Version)
|
||||
.then(result => {
|
||||
standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, {
|
||||
Result: result,
|
||||
.grabSkynetFileTree(data.Version)
|
||||
.then((result) => {
|
||||
standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, {
|
||||
Result: result,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Grab_Skynet_Tree_Reply,
|
||||
{},
|
||||
error
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(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,
|
||||
.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);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -3,18 +3,19 @@ const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
const path = require('path');
|
||||
|
||||
const getDirectories = source => {
|
||||
const getDirectories = (source) => {
|
||||
try {
|
||||
return fs.readdirSync(source, {withFileTypes: true})
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
return fs
|
||||
.readdirSync(source, { withFileTypes: true })
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const addListeners = ipcMain => {
|
||||
ipcMain.on(Constants.IPC_Get_State, event => {
|
||||
const addListeners = (ipcMain) => {
|
||||
ipcMain.on(Constants.IPC_Get_State, (event) => {
|
||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||
|
||||
let data = {};
|
||||
@@ -32,14 +33,16 @@ const addListeners = ipcMain => {
|
||||
AutoMount: false,
|
||||
AutoRestart: true,
|
||||
MountLocation: '',
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
data.RemoteMounts = data.RemoteMounts || [];
|
||||
data.S3Mounts = data.S3Mounts || [];
|
||||
|
||||
const remoteItems = getDirectories(path.join(helpers.getRepertoryDirectory(), 'remote'));
|
||||
const remoteItems = getDirectories(
|
||||
path.join(helpers.getRepertoryDirectory(), 'remote')
|
||||
);
|
||||
for (const dir of remoteItems) {
|
||||
const name = 'Remote' + dir.replace('_', ':');
|
||||
if (!data.RemoteMounts || data.RemoteMounts.indexOf(name) === -1) {
|
||||
@@ -52,7 +55,9 @@ const addListeners = ipcMain => {
|
||||
}
|
||||
}
|
||||
|
||||
const s3Items = getDirectories(path.join(helpers.getRepertoryDirectory(), 's3'));
|
||||
const s3Items = getDirectories(
|
||||
path.join(helpers.getRepertoryDirectory(), 's3')
|
||||
);
|
||||
for (const dir of s3Items) {
|
||||
const name = 'S3' + dir;
|
||||
if (!data.S3Mounts || data.S3Mounts.indexOf(name) === -1) {
|
||||
@@ -76,6 +81,4 @@ const addListeners = ipcMain => {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -2,7 +2,7 @@ const Constants = require('../../constants');
|
||||
const os = require('os');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, {closeApplication}) => {
|
||||
const addListeners = (ipcMain, { closeApplication }) => {
|
||||
ipcMain.on(Constants.IPC_Reboot_System, () => {
|
||||
if (os.platform() === 'win32') {
|
||||
helpers.executeAsync('shutdown.exe', ['/r', '/t', '30']);
|
||||
@@ -11,6 +11,4 @@ const addListeners = (ipcMain, {closeApplication}) => {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -3,7 +3,10 @@ const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
const os = require('os');
|
||||
|
||||
const addListeners = (ipcMain, {setIsInstalling, unmountAllDrives, standardIPCReply}) => {
|
||||
const addListeners = (
|
||||
ipcMain,
|
||||
{ setIsInstalling, unmountAllDrives, standardIPCReply }
|
||||
) => {
|
||||
ipcMain.on(Constants.IPC_Install_Upgrade, (event, data) => {
|
||||
let allowSkipVerification = true;
|
||||
|
||||
@@ -19,25 +22,34 @@ const addListeners = (ipcMain, {setIsInstalling, unmountAllDrives, standardIPCRe
|
||||
if (tempPub) {
|
||||
fs.unlinkSync(tempPub);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
const errorHandler = err => {
|
||||
const errorHandler = (err) => {
|
||||
cleanupFiles();
|
||||
setIsInstalling(false);
|
||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
|
||||
AllowSkipVerification: allowSkipVerification,
|
||||
Source: data.Source,
|
||||
}, err);
|
||||
standardIPCReply(
|
||||
event,
|
||||
Constants.IPC_Install_Upgrade_Reply,
|
||||
{
|
||||
AllowSkipVerification: allowSkipVerification,
|
||||
Source: data.Source,
|
||||
},
|
||||
err
|
||||
);
|
||||
};
|
||||
|
||||
// TODO Enable verification in 1.0.4
|
||||
const hasSignature = false;//!data.SkipVerification && data.Signature && (data.Signature.length > 0);
|
||||
const hasHash = false;//!data.SkipVerification && data.Sha256 && (data.Sha256.length > 0);
|
||||
const hasSignature = false; //! data.SkipVerification && data.Signature
|
||||
//! && (data.Signature.length > 0);
|
||||
const hasHash = false; //! data.SkipVerification && data.Sha256 &&
|
||||
//! (data.Sha256.length > 0);
|
||||
if (hasSignature) {
|
||||
try {
|
||||
const files = helpers.createSignatureFiles(data.Signature, Constants.DEV_PUBLIC_KEY);
|
||||
const files = helpers.createSignatureFiles(
|
||||
data.Signature,
|
||||
Constants.DEV_PUBLIC_KEY
|
||||
);
|
||||
tempPub = files.PublicKeyFile;
|
||||
tempSig = files.SignatureFile;
|
||||
} catch (e) {
|
||||
@@ -69,35 +81,37 @@ const addListeners = (ipcMain, {setIsInstalling, unmountAllDrives, standardIPCRe
|
||||
const executeInstall = () => {
|
||||
setIsInstalling(true);
|
||||
helpers
|
||||
.executeAsync(command, args)
|
||||
.then(() => {
|
||||
cleanupFiles();
|
||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply)
|
||||
})
|
||||
.catch(error => {
|
||||
setIsInstalling(false);
|
||||
errorHandler(error);
|
||||
});
|
||||
.executeAsync(command, args)
|
||||
.then(() => {
|
||||
cleanupFiles();
|
||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply);
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsInstalling(false);
|
||||
errorHandler(error);
|
||||
});
|
||||
};
|
||||
|
||||
if (hasSignature) {
|
||||
helpers
|
||||
.verifySignature(data.Source, tempSig, tempPub)
|
||||
.then(() => {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(Error('Failed to verify installation package signature'));
|
||||
});
|
||||
.verifySignature(data.Source, tempSig, tempPub)
|
||||
.then(() => {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(
|
||||
Error('Failed to verify installation package signature')
|
||||
);
|
||||
});
|
||||
} else if (hasHash) {
|
||||
helpers
|
||||
.verifyHash(data.Source, data.Sha256)
|
||||
.then(()=> {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(Error('Failed to verify installation package hash'));
|
||||
});
|
||||
.verifyHash(data.Source, data.Sha256)
|
||||
.then(() => {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(Error('Failed to verify installation package hash'));
|
||||
});
|
||||
} else {
|
||||
if (platform === 'darwin') {
|
||||
setTimeout(executeInstall, 3000);
|
||||
@@ -111,6 +125,4 @@ const addListeners = (ipcMain, {setIsInstalling, unmountAllDrives, standardIPCRe
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
module.exports = { addListeners };
|
||||
|
||||
@@ -57,7 +57,7 @@ export function register(config) {
|
||||
function registerValidSW(swUrl, config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
@@ -93,7 +93,7 @@ function registerValidSW(swUrl, config) {
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
@@ -101,7 +101,7 @@ function registerValidSW(swUrl, config) {
|
||||
function checkValidServiceWorker(swUrl, config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl)
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
@@ -109,7 +109,7 @@ function checkValidServiceWorker(swUrl, config) {
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
@@ -128,7 +128,7 @@ function checkValidServiceWorker(swUrl, config) {
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
|
||||
106
src/utils.js
106
src/utils.js
@@ -1,106 +0,0 @@
|
||||
import React from 'react';
|
||||
import * as Constants from './constants';
|
||||
import Modal from './components/UI/Modal/Modal';
|
||||
import axios from 'axios';
|
||||
|
||||
const ipcRenderer = (!process.versions.hasOwnProperty('electron') && window && window.require) ?
|
||||
window.require('electron').ipcRenderer :
|
||||
null;
|
||||
|
||||
export const checkNewReleases = selectedVersion => {
|
||||
let previousReleases = localStorage.getItem('previous_releases');
|
||||
if (previousReleases) {
|
||||
previousReleases = JSON.parse(previousReleases).VersionLookup;
|
||||
|
||||
let currentReleases = localStorage.getItem('releases');
|
||||
if (currentReleases) {
|
||||
currentReleases = JSON.parse(currentReleases).VersionLookup;
|
||||
return getNewReleases(previousReleases, currentReleases, selectedVersion);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
export const createModalConditionally = (condition, jsx, critical, disableFocusTrap, transparent) => {
|
||||
const modalProps = {critical: critical, disableFocusTrap: disableFocusTrap, transparent: transparent};
|
||||
return condition ? (<Modal {...modalProps}>{jsx}</Modal>) : null;
|
||||
};
|
||||
|
||||
export const extractFileNameFromURL = url => {
|
||||
const parts = url.split('/');
|
||||
return parts[parts.length - 1];
|
||||
};
|
||||
|
||||
export const formatLinesForDisplay = lines => {
|
||||
let msg = '';
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
if (i > 1) {
|
||||
msg += '\n';
|
||||
}
|
||||
msg += (lines[i].replace(/(\\#)/gm, '#') + '\n');
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
export const getChangesForRepertoryVersion = version => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = 'https://bitbucket.org/blockstorage/repertory/raw/' +
|
||||
Constants.REPERTORY_BRANCH + '/CHANGELOG.md';
|
||||
axios
|
||||
.get(url, {
|
||||
responseType: 'text',
|
||||
})
|
||||
.then(response => {
|
||||
try {
|
||||
let found = false;
|
||||
let ended = false;
|
||||
let lines = response.data
|
||||
.replace(/(\r\n)/gm, '\n')
|
||||
.split('\n')
|
||||
.filter(l => {
|
||||
return !ended && (l.length > 0) && (found
|
||||
? !(ended = l.startsWith('## '))
|
||||
: (found = l.startsWith(`## ${version}`)));
|
||||
});
|
||||
resolve(lines);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getIPCRenderer = () => {
|
||||
return ipcRenderer;
|
||||
};
|
||||
|
||||
export const getNewReleases = (existingLocations, newLocations, selectedVersion) => {
|
||||
const ret = [];
|
||||
if (existingLocations && newLocations) {
|
||||
Constants.RELEASE_TYPES.forEach(release => {
|
||||
newLocations[release]
|
||||
.filter(version => (version !== selectedVersion) && !existingLocations[release].includes(version) && (version !== 'unavailable'))
|
||||
.forEach(version => {
|
||||
ret.splice(0, 0, {
|
||||
Display: version,
|
||||
Release: Constants.RELEASE_TYPES.indexOf(release),
|
||||
Version: newLocations[release].indexOf(version),
|
||||
VersionString: version,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
export const getSelectedVersionFromState = state => {
|
||||
return (state.relver.Version === -1) ?
|
||||
'unavailable' :
|
||||
state.relver.VersionLookup[Constants.RELEASE_TYPES[state.relver.Release]][state.relver.Version];
|
||||
};
|
||||
|
||||
134
src/utils.jsx
Normal file
134
src/utils.jsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import axios from 'axios';
|
||||
import React from 'react';
|
||||
|
||||
import Modal from './components/UI/Modal/Modal';
|
||||
import * as Constants from './constants';
|
||||
|
||||
const ipcRenderer =
|
||||
!process.versions.hasOwnProperty('electron') && window && window.require
|
||||
? window.require('electron').ipcRenderer
|
||||
: null;
|
||||
|
||||
export const checkNewReleases = (selectedVersion) => {
|
||||
let previousReleases = localStorage.getItem('previous_releases');
|
||||
if (previousReleases) {
|
||||
previousReleases = JSON.parse(previousReleases).VersionLookup;
|
||||
|
||||
let currentReleases = localStorage.getItem('releases');
|
||||
if (currentReleases) {
|
||||
currentReleases = JSON.parse(currentReleases).VersionLookup;
|
||||
return getNewReleases(previousReleases, currentReleases, selectedVersion);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
export const createModalConditionally = (
|
||||
condition,
|
||||
jsx,
|
||||
critical,
|
||||
disableFocusTrap,
|
||||
transparent
|
||||
) => {
|
||||
const modalProps = {
|
||||
critical: critical,
|
||||
disableFocusTrap: disableFocusTrap,
|
||||
transparent: transparent,
|
||||
};
|
||||
return condition ? <Modal {...modalProps}>{jsx}</Modal> : null;
|
||||
};
|
||||
|
||||
export const extractFileNameFromURL = (url) => {
|
||||
const parts = url.split('/');
|
||||
return parts[parts.length - 1];
|
||||
};
|
||||
|
||||
export const formatLinesForDisplay = (lines) => {
|
||||
let msg = '';
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
if (i > 1) {
|
||||
msg += '\n';
|
||||
}
|
||||
msg += lines[i].replace(/(\\#)/gm, '#') + '\n';
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
export const getChangesForRepertoryVersion = (version) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url =
|
||||
'https://bitbucket.org/blockstorage/repertory/raw/' +
|
||||
Constants.REPERTORY_BRANCH +
|
||||
'/CHANGELOG.md';
|
||||
axios
|
||||
.get(url, {
|
||||
responseType: 'text',
|
||||
})
|
||||
.then((response) => {
|
||||
try {
|
||||
let found = false;
|
||||
let ended = false;
|
||||
let lines = response.data
|
||||
.replace(/(\r\n)/gm, '\n')
|
||||
.split('\n')
|
||||
.filter((l) => {
|
||||
return (
|
||||
!ended &&
|
||||
l.length > 0 &&
|
||||
(found
|
||||
? !(ended = l.startsWith('## '))
|
||||
: (found = l.startsWith(`## ${version}`)))
|
||||
);
|
||||
});
|
||||
resolve(lines);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getIPCRenderer = () => {
|
||||
return ipcRenderer;
|
||||
};
|
||||
|
||||
export const getNewReleases = (
|
||||
existingLocations,
|
||||
newLocations,
|
||||
selectedVersion
|
||||
) => {
|
||||
const ret = [];
|
||||
if (existingLocations && newLocations) {
|
||||
Constants.RELEASE_TYPES.forEach((release) => {
|
||||
newLocations[release]
|
||||
.filter(
|
||||
(version) =>
|
||||
version !== selectedVersion &&
|
||||
!existingLocations[release].includes(version) &&
|
||||
version !== 'unavailable'
|
||||
)
|
||||
.forEach((version) => {
|
||||
ret.splice(0, 0, {
|
||||
Display: version,
|
||||
Release: Constants.RELEASE_TYPES.indexOf(release),
|
||||
Version: newLocations[release].indexOf(version),
|
||||
VersionString: version,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
export const getSelectedVersionFromState = (state) => {
|
||||
return state.relver.Version === -1
|
||||
? 'unavailable'
|
||||
: state.relver.VersionLookup[Constants.RELEASE_TYPES[state.relver.Release]][
|
||||
state.relver.Version
|
||||
];
|
||||
};
|
||||
Reference in New Issue
Block a user