diff --git a/CHANGELOG.md b/CHANGELOG.md index b7fccaa..49e570f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,29 @@ # Changelog +## 1.1.2 +* Style changes + +## 1.1.1 +* \#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 + ## 1.0.11 (Linux only) * Fix Ubuntu 19.10 detection -## 1.0.10 (Windows only) +## 1.0.10 +* 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) ## 1.0.8 diff --git a/README.md b/README.md index bbf9491..ddf8427 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ # Repertory UI -![alt text](https://i.ibb.co/s6Qpnwk/Screen-Shot-2019-08-31-at-2-14-48-AM.png) +![alt text](https://i.ibb.co/7Xwcqbd/repertor-ui-1-1-1.png) ## GUI for [Repertory](https://bitbucket.org/blockstorage/repertory) -Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions via FUSE on Linux/OS X or via WinFSP on Windows. +Repertory allows you to mount Sia and/or ScPrime blockchain storage solutions via FUSE on Linux/OS X or via WinFSP on Windows. ## Requirements * Sia >=1.4.1 -* SiaPrime >=1.4.0 +* ScPrime >=1.4.1.2 ## Downloads -* **Repertory UI v1.0.11 Linux 64-bit** [](https://pixeldrain.com/u/cP4E5Aia) [](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage) +* **Repertory UI v1.1.2 Linux 64-bit** [](https://pixeldrain.com/u/5i1mA1gb) [](https://bitbucket.org/blockstorage/repertory/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage) * NOTE: Linux distributions require `fuse` and `libfuse` to be installed. -* **Repertory UI v1.0.8 OS X 64-bit** [](https://pixeldrain.com/u/6NjT6uEl) [](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_mac.dmg) -* **Repertory UI v1.0.10 Windows 64-bit** [](https://pixeldrain.com/u/YCzKB0a9) [](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.10_win.exe) +* **Repertory UI v1.1.2 OS X 64-bit** [](https://pixeldrain.com/u/jEWmNDRX) [](https://bitbucket.org/blockstorage/repertory/downloads/repertory-ui_1.1.2_mac.dmg) +* **Repertory UI v1.1.2 Windows 64-bit** [](https://pixeldrain.com/u/TkQn25Bm) [](https://bitbucket.org/blockstorage/repertory/downloads/repertory-ui_1.1.2_win.exe) ## Supported Platforms * OS X 64-bit @@ -29,8 +29,10 @@ Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions v * Fedora 28 * Fedora 29 * Fedora 30 + * Fedora 31 * Linux Mint 19 * Linux Mint 19.1 + * Linux Mint 19.2 * Manjaro * Uses `Ubuntu 18.10` binaries for compatibility * OpenSUSE Leap 15.0 @@ -40,12 +42,18 @@ Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions v * Ubuntu 18.04 * Ubuntu 18.10 * Ubuntu 19.04 - * Ubuntu 19.10 - * Uses `Ubuntu 19.04` binaries for compatibility + * Ubuntu 19.10 ## Issues/Suggestions Please submit [here](https://bitbucket.org/blockstorage/repertory-ui/issues?status=new&status=open) +## Remote Mount +This feature allows you to share your mounts with other PC's and mount them remotely. +### Enabling Remote Mount for Sharing +[Watch Demo](src/assets/images/Enable_Remote_Mount.gif) +### Connecting to a Remote Mount +[Watch Demo](src/assets/images/Connect_To_Remote.gif) + ## The FAQ of One ### My distro isn't listed... Why? It may still function properly as long as it derives from one listed above. I do plan to test more, so this list should grow over time. diff --git a/create_dist.cmd b/create_dist.cmd index 3743bd9..ba1ec57 100644 --- a/create_dist.cmd +++ b/create_dist.cmd @@ -26,6 +26,8 @@ pushd "%ROOT%" ) set OUT_FILE=repertory-ui_%APP_VER%_win.exe + call npm install + call npm run dist && ( pushd dist (certutil -hashfile "%OUT_FILE%" SHA256 | %SED_BIN% -e "1d" -e "$d" -e "s/\ //g") > "%OUT_FILE%.sha256" || (call :ERROR "Create sha-256 failed") diff --git a/create_dist.sh b/create_dist.sh index 8986829..aa98e53 100755 --- a/create_dist.sh +++ b/create_dist.sh @@ -19,7 +19,7 @@ if beginsWith darwin "$OSTYPE"; then JQ_EXEC=jq-osx-amd64 SHA256_EXEC="shasum -a 256 -b" else - DISTRO_LIST="arch centos7 debian9 debian10 fedora28 fedora29 fedora30 opensuse15 opensuse15.1 solus tumbleweed ubuntu18.04 ubuntu18.10 ubuntu19.04" + DISTRO_LIST="arch centos7 debian9 debian10 fedora28 fedora29 fedora30 fedora31 opensuse15 opensuse15.1 solus tumbleweed ubuntu18.04 ubuntu18.10 ubuntu19.04 ubuntu19.10" OUT_FILE=repertory-ui_${APP_VER}_linux_x86_64.AppImage BASE64_EXEC="base64 -w0" JQ_EXEC=jq-linux64 @@ -38,6 +38,8 @@ upload_to_bitbucket() { chmod +x "bin/${JQ_EXEC}" || exit_script "chmod +x ${JQ_EXEC} failed" +npm install + if npm run dist; then cd dist ${SHA256_EXEC} ${OUT_FILE} > ${OUT_FILE}.sha256 || exit_script "Create sha256 failed" diff --git a/images/blue/icon_24X24.png b/images/blue/icon_24X24.png new file mode 100644 index 0000000..7f4dad4 Binary files /dev/null and b/images/blue/icon_24X24.png differ diff --git a/images/blue/icon_40x40.png b/images/blue/icon_40x40.png new file mode 100644 index 0000000..9ac8d41 Binary files /dev/null and b/images/blue/icon_40x40.png differ diff --git a/images/blue/icon_48x48.png b/images/blue/icon_48x48.png new file mode 100644 index 0000000..b226037 Binary files /dev/null and b/images/blue/icon_48x48.png differ diff --git a/images/blue/logo.icns b/images/blue/logo.icns new file mode 100644 index 0000000..5e1828b Binary files /dev/null and b/images/blue/logo.icns differ diff --git a/images/blue/logo.iconset/icon_128x128.png b/images/blue/logo.iconset/icon_128x128.png new file mode 100644 index 0000000..7399beb Binary files /dev/null and b/images/blue/logo.iconset/icon_128x128.png differ diff --git a/images/blue/logo.iconset/icon_128x128@2x.png b/images/blue/logo.iconset/icon_128x128@2x.png new file mode 100644 index 0000000..92a92dd Binary files /dev/null and b/images/blue/logo.iconset/icon_128x128@2x.png differ diff --git a/images/blue/logo.iconset/icon_16x16.png b/images/blue/logo.iconset/icon_16x16.png new file mode 100644 index 0000000..7136174 Binary files /dev/null and b/images/blue/logo.iconset/icon_16x16.png differ diff --git a/images/blue/logo.iconset/icon_16x16@2x.png b/images/blue/logo.iconset/icon_16x16@2x.png new file mode 100644 index 0000000..711f339 Binary files /dev/null and b/images/blue/logo.iconset/icon_16x16@2x.png differ diff --git a/images/blue/logo.iconset/icon_256x256.png b/images/blue/logo.iconset/icon_256x256.png new file mode 100644 index 0000000..92a92dd Binary files /dev/null and b/images/blue/logo.iconset/icon_256x256.png differ diff --git a/images/blue/logo.iconset/icon_256x256@2x.png b/images/blue/logo.iconset/icon_256x256@2x.png new file mode 100644 index 0000000..f168b54 Binary files /dev/null and b/images/blue/logo.iconset/icon_256x256@2x.png differ diff --git a/images/blue/logo.iconset/icon_32x32.png b/images/blue/logo.iconset/icon_32x32.png new file mode 100644 index 0000000..711f339 Binary files /dev/null and b/images/blue/logo.iconset/icon_32x32.png differ diff --git a/images/blue/logo.iconset/icon_32x32@2x.png b/images/blue/logo.iconset/icon_32x32@2x.png new file mode 100644 index 0000000..073d949 Binary files /dev/null and b/images/blue/logo.iconset/icon_32x32@2x.png differ diff --git a/images/blue/logo.iconset/icon_512x512.png b/images/blue/logo.iconset/icon_512x512.png new file mode 100644 index 0000000..f168b54 Binary files /dev/null and b/images/blue/logo.iconset/icon_512x512.png differ diff --git a/images/blue/logo.iconset/icon_512x512@2x.png b/images/blue/logo.iconset/icon_512x512@2x.png new file mode 100644 index 0000000..fb28f9d Binary files /dev/null and b/images/blue/logo.iconset/icon_512x512@2x.png differ diff --git a/images/blue/logo.iconset/icon_64x64.png b/images/blue/logo.iconset/icon_64x64.png new file mode 100644 index 0000000..073d949 Binary files /dev/null and b/images/blue/logo.iconset/icon_64x64.png differ diff --git a/images/blue/logo.iconset/icon_64x64@2x.png b/images/blue/logo.iconset/icon_64x64@2x.png new file mode 100644 index 0000000..7399beb Binary files /dev/null and b/images/blue/logo.iconset/icon_64x64@2x.png differ diff --git a/images/blue/logo.iconset/logo_1024x1024.png b/images/blue/logo.iconset/logo_1024x1024.png new file mode 100644 index 0000000..fb28f9d Binary files /dev/null and b/images/blue/logo.iconset/logo_1024x1024.png differ diff --git a/images/green/icon_24X24.png b/images/green/icon_24X24.png new file mode 100644 index 0000000..eda16c4 Binary files /dev/null and b/images/green/icon_24X24.png differ diff --git a/images/green/icon_40x40.png b/images/green/icon_40x40.png new file mode 100644 index 0000000..09fee09 Binary files /dev/null and b/images/green/icon_40x40.png differ diff --git a/images/green/icon_48x48.png b/images/green/icon_48x48.png new file mode 100644 index 0000000..a9901a5 Binary files /dev/null and b/images/green/icon_48x48.png differ diff --git a/images/green/logo.icns b/images/green/logo.icns new file mode 100644 index 0000000..ca85046 Binary files /dev/null and b/images/green/logo.icns differ diff --git a/images/green/logo.iconset/icon_128x128.png b/images/green/logo.iconset/icon_128x128.png new file mode 100644 index 0000000..563e25b Binary files /dev/null and b/images/green/logo.iconset/icon_128x128.png differ diff --git a/images/green/logo.iconset/icon_128x128@2x.png b/images/green/logo.iconset/icon_128x128@2x.png new file mode 100644 index 0000000..531a746 Binary files /dev/null and b/images/green/logo.iconset/icon_128x128@2x.png differ diff --git a/images/green/logo.iconset/icon_16x16.png b/images/green/logo.iconset/icon_16x16.png new file mode 100644 index 0000000..9232da4 Binary files /dev/null and b/images/green/logo.iconset/icon_16x16.png differ diff --git a/images/green/logo.iconset/icon_16x16@2x.png b/images/green/logo.iconset/icon_16x16@2x.png new file mode 100644 index 0000000..ea39c61 Binary files /dev/null and b/images/green/logo.iconset/icon_16x16@2x.png differ diff --git a/images/green/logo.iconset/icon_256x256.png b/images/green/logo.iconset/icon_256x256.png new file mode 100644 index 0000000..ea3dca0 Binary files /dev/null and b/images/green/logo.iconset/icon_256x256.png differ diff --git a/images/green/logo.iconset/icon_256x256@2x.png b/images/green/logo.iconset/icon_256x256@2x.png new file mode 100644 index 0000000..af7cdbe Binary files /dev/null and b/images/green/logo.iconset/icon_256x256@2x.png differ diff --git a/images/green/logo.iconset/icon_32x32.png b/images/green/logo.iconset/icon_32x32.png new file mode 100644 index 0000000..408cf81 Binary files /dev/null and b/images/green/logo.iconset/icon_32x32.png differ diff --git a/images/green/logo.iconset/icon_32x32@2x.png b/images/green/logo.iconset/icon_32x32@2x.png new file mode 100644 index 0000000..f01cbd3 Binary files /dev/null and b/images/green/logo.iconset/icon_32x32@2x.png differ diff --git a/images/green/logo.iconset/icon_512x512.png b/images/green/logo.iconset/icon_512x512.png new file mode 100644 index 0000000..7b43993 Binary files /dev/null and b/images/green/logo.iconset/icon_512x512.png differ diff --git a/images/green/logo.iconset/icon_512x512@2x.png b/images/green/logo.iconset/icon_512x512@2x.png new file mode 100644 index 0000000..e712579 Binary files /dev/null and b/images/green/logo.iconset/icon_512x512@2x.png differ diff --git a/images/green/logo.iconset/icon_64x64.png b/images/green/logo.iconset/icon_64x64.png new file mode 100644 index 0000000..0a97ba7 Binary files /dev/null and b/images/green/logo.iconset/icon_64x64.png differ diff --git a/images/green/logo.iconset/icon_64x64@2x.png b/images/green/logo.iconset/icon_64x64@2x.png new file mode 100644 index 0000000..fb19446 Binary files /dev/null and b/images/green/logo.iconset/icon_64x64@2x.png differ diff --git a/images/green/logo.iconset/logo_1024x1024.png b/images/green/logo.iconset/logo_1024x1024.png new file mode 100644 index 0000000..af98d2b Binary files /dev/null and b/images/green/logo.iconset/logo_1024x1024.png differ diff --git a/images/logo_blue.xcf b/images/logo_blue.xcf new file mode 100644 index 0000000..2fc3c12 Binary files /dev/null and b/images/logo_blue.xcf differ diff --git a/images/logo_green.xcf b/images/logo_green.xcf new file mode 100644 index 0000000..e7fd31b Binary files /dev/null and b/images/logo_green.xcf differ diff --git a/logo.xcf b/logo.xcf deleted file mode 100644 index 3b73421..0000000 Binary files a/logo.xcf and /dev/null differ diff --git a/package.json b/package.json index 08a0fbf..e59e0ff 100644 --- a/package.json +++ b/package.json @@ -1,37 +1,38 @@ { "name": "repertory-ui", - "version": "1.0.11", + "version": "1.1.2", "private": true, "author": "scott.e.graves@protonmail.com", - "description": "GUI for Repertory - Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions via FUSE on Linux/OS X or via WinFSP on Windows.", + "description": "GUI for Repertory - Repertory allows you to mount Sia and/or ScPrime blockchain storage solutions via FUSE on Linux/OS X or via WinFSP on Windows.", "dependencies": { - "@fortawesome/fontawesome-svg-core": "^1.2.22", - "@fortawesome/free-solid-svg-icons": "^5.10.2", - "@fortawesome/react-fontawesome": "^0.1.4", + "@fortawesome/fontawesome-svg-core": "^1.2.25", + "@fortawesome/free-solid-svg-icons": "^5.11.2", + "@fortawesome/react-fontawesome": "^0.1.7", "auto-launch": "^5.0.5", - "axios": "^0.18.1", - "electron-debug": "^2.2.0", + "axios": "^0.19.0", + "devtron": "^1.4.0", + "electron-debug": "^3.0.1", "font-awesome": "^4.7.0", "node-schedule": "^1.3.2", "randomstring": "^1.1.5", - "react": "^16.9.0", - "react-dom": "^16.9.0", - "react-loader-spinner": "^2.3.0", - "react-redux": "^7.1.1", - "react-scripts": "2.1.8", - "react-tooltip": "^3.10.0", + "react": "^16.11.0", + "react-dom": "^16.11.0", + "react-loader-spinner": "^3.1.4", + "react-redux": "^7.1.3", + "react-scripts": "3.2.0", + "react-tooltip": "^3.11.1", "redux": "^4.0.4", - "redux-starter-kit": "^0.5.1", + "redux-starter-kit": "^1.0.1", "redux-thunk": "^2.3.0", - "unzipper": "^0.9.15", + "unzipper": "^0.10.5", "winreg": "^1.2.4" }, "devDependencies": { - "cross-env": "^5.2.0", - "electron": "^4.2.9", + "cross-env": "^6.0.3", + "electron": "^5.0.12", "electron-builder": "^20.44.4", "extract-text-webpack-plugin": "^3.0.2", - "typescript": "^3.5.3", + "typescript": "^3.7.2", "webpack-browser-plugin": "^1.0.20" }, "scripts": { @@ -70,8 +71,7 @@ "node_modules/**/*", "src/helpers.js", "src/renderer/**/*", - "public/detect_linux.sh", - "public/install_linux.sh" + "public/detect_linux.sh" ], "linux": { "category": "Utility", @@ -79,9 +79,9 @@ }, "mac": { "category": "public.app-category.utilities", - "icon": "./build/icon_color.icns", "target": "dmg", - "darkModeSupport": true + "darkModeSupport": true, + "icon": "./build/icon.icns" }, "win": { "icon": "./build/icon.ico", diff --git a/public/detect_linux.sh b/public/detect_linux.sh index c33aae2..51f51f7 100644 --- a/public/detect_linux.sh +++ b/public/detect_linux.sh @@ -18,17 +18,11 @@ if [ -f /etc/centos-release ]; then fi elif [ -f /etc/fedora-release ]; then . /etc/os-release - if [ "$VERSION_ID" = "30" ]; then - DISTNAME=fedora - DISTVER=30 - elif [ "$VERSION_ID" = "29" ]; then - DISTNAME=fedora - DISTVER=29 - elif [ "$VERSION_ID" = "28" ]; then - DISTNAME=fedora - DISTVER=28 - else + if [ "$VERSION_ID" != "31" ] && [ "$VERSION_ID" != "30" ] && [ "$VERSION_ID" != "29" ] && [ "$VERSION_ID" != "28" ]; then resetDistVer + else + DISTNAME=fedora + DISTVER=$VERSION_ID fi elif [ -f /etc/solus-release ]; then DISTNAME=solus @@ -38,7 +32,7 @@ elif [ -f /etc/lsb-release ]; then DISTVER=${DISTRIB_RELEASE} if [ "$DISTNAME" != "ubuntu" ]; then if [ "$DISTNAME" = "linuxmint" ]; then - if [ "$DISTVER" = "19" ] || [ "$DISTVER" = "19.1" ]; then + if [ "$DISTVER" = "19" ] || [ "$DISTVER" = "19.1" ] || [ "$DISTVER" = "19.2" ]; then DISTNAME=ubuntu DISTVER=18.04 else @@ -54,18 +48,18 @@ elif [ -f /etc/lsb-release ]; then else resetDistVer fi - elif [ "$DISTVER" = "19.10" ]; then - DISTVER=19.04 + elif [ "$DISTVER" != "18.04" ] && [ "$DISTVER" != "18.10" ] && [ "$DISTVER" != "19.04" ] && [ "$DISTVER" != "19.10" ]; then + resetDistVer fi -elif [ -f /etc/debian_version ]; then +fi + +if [ "$DISTNAME" = "unknown" ] && [ -f /etc/debian_version ]; then DISTNAME=debian DISTVER=$(head -1 /etc/debian_version|awk -F. '{print $1}') - if [ "$DISTVER" != "9" ]; then - if [ "$DISTVER" != "10" ]; then - resetDistVer - fi + if [ "$DISTVER" != "9" ] && [ "$DISTVER" != "10" ]; then + resetDistVer fi -fi +fi if [ "$DISTNAME" = "unknown" ]; then if [ -f /etc/os-release ]; then @@ -96,4 +90,4 @@ if [ "$DISTNAME" = "unknown" ]; then fi fi -echo ${DISTNAME}${DISTVER} \ No newline at end of file +echo ${DISTNAME}${DISTVER} diff --git a/public/electron.js b/public/electron.js index a4741d6..2f8270b 100644 --- a/public/electron.js +++ b/public/electron.js @@ -14,7 +14,12 @@ const helpers = require('../src/helpers'); const os = require('os'); const path = require('path'); const url = require('url'); -require('electron-debug/index')(); +const debug = require('electron-debug'); +debug({ + devToolsMode: 'undocked', + isEnabled: true, + showDevTools: !!process.env.ELECTRON_START_URL, +}); require.extensions['.sh'] = function (module, filename) { module.exports = fs.readFileSync(filename, 'utf8'); @@ -34,6 +39,13 @@ const StateIPC = require('../src/renderer/ipc/StateIPC'); const SystemIPC = require('../src/renderer/ipc/SystemIPC'); const UpgradeIPC = require('../src/renderer/ipc/UpgradeIPC'); +const platform = os.platform(); + +const dimensions = { + height: ((platform === 'darwin') ? 346 : (platform === 'win32') ? 326 : 300), + width: 428 + ((platform === 'win32') ? 40 : (platform === 'darwin') ? 190 : 200), +}; + let isShutdown = false; let isQuiting = false; let isInstalling = false; @@ -70,28 +82,32 @@ const createWindow = () => { loadUiSettings(); let extra = {}; - if (os.platform() === 'linux') { + if (platform === 'linux') { extra = { - icon: path.join(__dirname, '../', 'icon.png'), + icon: path.join(__dirname, '../build/', 'logo.png'), } } // Create the browser window. - const height = (process.env.ELECTRON_START_URL || (os.platform() === 'darwin') ? 294 : 274) - ((os.platform() === 'win32') ? 0 : 20); mainWindow = new BrowserWindow({ - width: 428 + ((os.platform() === 'win32') ? 0 : (os.platform() === 'darwin') ? 150 : 160), - height: height, + height: dimensions.height, + width: dimensions.width, fullscreen: false, resizable: false, show: !launchHidden, title: 'Repertory UI', ...extra, webPreferences: { + nodeIntegration: true, webSecurity: !process.env.ELECTRON_START_URL } }); - - if ((os.platform() === 'darwin') && launchHidden) { + if (platform === 'linux') { + mainWindow.setMenuBarVisibility(false); + } else { + mainWindow.removeMenu(); + } + if ((platform === 'darwin') && launchHidden) { app.dock.hide(); } @@ -121,8 +137,8 @@ const createWindow = () => { MountsIPC.unmountAllDrives(); }); - const appPath = (os.platform() === 'win32') ? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')) : - (os.platform() === 'darwin') ? path.resolve(path.join(path.dirname(app.getAppPath()), '../MacOS/repertory-ui')) : + 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({ @@ -166,19 +182,19 @@ const createWindow = () => { } ]); - const image = nativeImage.createFromPath(path.join(__dirname, (os.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 - .isEnabled() - .then((enabled) => { - trayContextMenu.items[1].checked = enabled; - mainWindowTray.setToolTip('Repertory UI'); - mainWindowTray.setContextMenu(trayContextMenu) - }) - .catch(() => { - closeApplication(); - }); + .isEnabled() + .then((enabled) => { + trayContextMenu.items[1].checked = enabled; + mainWindowTray.setToolTip('Repertory UI'); + mainWindowTray.setContextMenu(trayContextMenu) + }) + .catch(() => { + closeApplication(); + }); mainWindow.loadURL(startUrl); }; @@ -188,7 +204,7 @@ const getMainWindow = () => { }; const loadUiSettings = () => { - const settingFile = path.join(helpers.resolvePath(Constants.DATA_LOCATIONS[os.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')); @@ -217,9 +233,9 @@ const setIsInstalling = installing => { const setTrayImage = driveInUse => { let image; if (driveInUse) { - image = nativeImage.createFromPath(path.join(__dirname, os.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, os.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); }; @@ -227,8 +243,10 @@ const setTrayImage = driveInUse => { const setWindowVisibility = show => { if (show) { mainWindow.show(); - if (os.platform() === 'darwin') { + if (platform === 'darwin') { app.dock.show(); + } else if (platform === 'linux') { + mainWindow.setSize(dimensions.width, dimensions.height); } if (mainWindow.isMinimized()) { @@ -237,7 +255,7 @@ const setWindowVisibility = show => { mainWindow.focus(); } else { mainWindow.hide(); - if (os.platform() === 'darwin') { + if (platform === 'darwin') { app.dock.hide(); } } @@ -260,9 +278,6 @@ const standardIPCReply = (event, channel, data, error) => { } }; - - - app.on('before-quit', function () { isQuiting = true; }); diff --git a/public/favicon.ico b/public/favicon.ico index 1c44c7e..ca63e58 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/icon.icns b/public/icon.icns index 09d18e9..5e1828b 100644 Binary files a/public/icon.icns and b/public/icon.icns differ diff --git a/public/icon.ico b/public/icon.ico index 1c44c7e..ca63e58 100644 Binary files a/public/icon.ico and b/public/icon.ico differ diff --git a/public/icon_color.icns b/public/icon_color.icns deleted file mode 100644 index 6f2482b..0000000 Binary files a/public/icon_color.icns and /dev/null differ diff --git a/public/logo.png b/public/logo.png index 56d6c12..10bea75 100644 Binary files a/public/logo.png and b/public/logo.png differ diff --git a/public/logo_both.png b/public/logo_both.png index 4010799..5e3b52d 100644 Binary files a/public/logo_both.png and b/public/logo_both.png differ diff --git a/public/logo_both_mac.png b/public/logo_both_mac.png index 849bbb1..eda16c4 100644 Binary files a/public/logo_both_mac.png and b/public/logo_both_mac.png differ diff --git a/public/logo_mac.png b/public/logo_mac.png index 0836d8e..7f4dad4 100644 Binary files a/public/logo_mac.png and b/public/logo_mac.png differ diff --git a/releases.json b/releases.json index d373548..d30edbf 100644 --- a/releases.json +++ b/releases.json @@ -1,220 +1,246 @@ { "Locations": { "arch": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "centos7": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "darwin": { - "1.0.8": { - "sha256": "fa978eeb6f5456c1fcea902cafb039eeda6d13f93770150564a0253341cb3d63", - "sig": "CfzV0Jl/Saq6Yqtwz21Qm5F7C/geGtmotifZrUcSFpGTaniYbtWtwJSap1tAep1EzL43l4wtxmpDM9EJ3qkquD6JMQjKK89twYotzMoWneZyyEB7obhpi/M3mfih8fYrPCgxaUkVm4DZ4DNbZn2GwjMmdCV698OnUfg2PKhVH4LnjqekqOEsU02B/cvlym2zPLLoEhjJoL8+s2ICIV3WBVDHpcF4ZF3lnI8HgfjjpvhQ+V8LQCk+LQTzIwwBDj6C1sH5V9om7ZUyZZEQk8ALcvo6EJHhhOoQ6extou5NIfBSkDir9IJW8hnTVykgYwoFXSUSAf7tvLn/fx+xpvp27hh+MQqA7KPhVyUD0I2qobm87KV9RBUuW0eqC/ijkcfacyhBnTEikSrHbew3cy69KtBTs4xaicIErQogJXcRfn0bQsVYxk1H3lRyoZnnaFliLwBw/8NQnrvjZqMiqlVXijZj6w0gWZjfrJ/s7UZ0K+yofVAyp3Qzf8JsdlUeCS+lqsv65ANWOBrUeF2Tz2neIWWISnVADmBMeacp/Xuz/bwuGLc4FnMWyhIBjBGwYLBTiaq0nk0oC6wn7a+LZoib8WtU9CAJ4v82k0e8YgiwBDPZPfU03wWWVJoRC2yUu89/6x8AQaClwNh364XWmF7bgbCyjThjC70iz2Feu0ORkj4D0vjClYnP1Kz5HOAvzCRlJTtwVnB9xrEBtV45ONaw6wRwVPkADLg/624FTHzwpi7BTTV2xCAn3kx2JvSH7n9ISySu8ZG6Z2pZ5IBs7+7jWQKmtbC8b6wB0VpYwoCcLjGIduaYtx2YKv0FvjMxOeMmrfu3X33Ab9KL/T4meu5LhqcW01JDP2MlzZ8UYebykd+0KI2mts+hGHNhCT3/d7fEh/ccmaJQ1sNl8VoKos1DlwUL+U8t7PVUNj6e4SXZK+Na9pPLI3pMPKvaoPZimbXRKShF+mYUGlLEcQLcjFTTmOnFSkIP39pa98K7mtTwy50dgcqroTm9rAoBGLcicjdlOi76XcSikYrYrBupx2LtAiWUuXrD0Zm9lQ/Lfwp3smUaC6aFNmnyxPmDJ1XscbQr3m/5oxfNopBNliZCvlGLUc/HGUpy0XcEZymPA77AZog4cHcjgAi9tsdnPHfxMmFTniThDD/SgVjTolzSu4Sm/RY2K2hCJ8qFeSuvbhmgPPWOBbNMOfsv9Nswa4Rd57uEqxxSrpAo1dzxdJPklrDsCxeexVz1/6xW3Qj+I12abMacCCa8oX+PLfpdT6hDqBSlzT3KbVz6ApWNRheM/z8kwpDCDHKGIKPZ5OjRm0SRn/SlogRCUHZ93TSOClIPRr37TDYDpvzeoSjAxnwQ2jTxuIs=", + "1.1.2": { + "sha256": "0c9c4de2006ecc4ecc6166af979cc5e0b66212472d21c542d4198013e354e275", + "sig": "CFzIk/7FJbhem38KzK1N37Z5g55wNeyvWZDC4rYElLxC6VEA2f4ZQym9sy47TDKamli42/IsiBSkm+1rE8Isg9AxdkYxv0TBbpBxm0W+vVaiHSHfrp4qQ3ciaxgPUiph6svAKZSIfw5pGtCshEaUlLBSMGGY4+Hi9aoH6yZojyFfhzKQP1AZbCVE5ZB7EStgg9LxzJ9U3dQZXon5G5LiZTRILPJ6XUiXKNlMzZ/DLCioMOQGnGqeDv2CDxXAaBNPdSzEz4cwti9FBBhIOhl/XIZN4i653f3zIHTn7HjJHWCn4wnhOB3fV18dxYv3I3laDXnlOwW1NCL3EVP+wlZI7fi4z5k5BntVC0+xnvPEKWWPnoDUDah1mjDQoIvX8espi0FoglOLW6qiToq5smYu9Hptkrw6ExAyvTRBZ92ythSFgzgZ/LtmQqN7aoutDA1CDp2JFkBBLu03vch22x5JUI47v6EZKHTfLe667UXBctF+xLVw0AXQdpQIVqAV4mHKx4zwlgZhk/iflGRy5OWDwIQ7Nc+CzY+u6UOI5gqEuHa2h23BickstbLHl+Qd5vK4BZf70Z+mt5M8IRQ3EXztEVhmapRQSmOlEkvEjPaHMzly95k/LpsQxrA7mxwQd5kQSptERzFQ1dKuolUwwMTjcUZPZn5ATv1bVIMtCBmXlrRd6S2liFgatnP+HCu3LnHOlkfuXWjOqL0EuFzWlTC6646SDDMqrju+z95HYpXiGDu4EI3XhXd/67AiTQdj828MNo417FlkuuVTqsLOiKY18KMx9zYyDgWzyQZ9vXUbMwrLpYB6FWLfKxwKjyA/c+tLO52D/WzUkeX+XmJPlRSi2xsjvH/5e/z6uEvqafLPwH3BnaQEsWsrRd7hludfWej4EelxW2ec+4whMkJtIXpFrX+hnxHhs7U15QjDVbq2CARjuto+4EWo5iAO+BkK+OgxyfCEBAM9yrpqyjiQXwXi6imVj6CuOu8z+LgPBrC8bdl9pfURrmnxubZKYH2NQ06YcJs1ezeipRVMJgq4VyuMcs+0zg/wMYYdAuPVbLiVzRj9IjlMgaRoZqt5goPtjg2M7OkLemy3dcmusWakQ4ylw8Jsng00K4VlBKGTNr/HbThIZpBkCVUmVpUEKlrxGUsYaNz/TzrVTYQF3jBuk7wPXiD4pFXn49LuOpI9p+LsFCZnjxHJMBg+WSkcFpoJ0NMU2tC64ksEYrvY3BO+L2/dAUQ/2yQ0HLnnIXHSQhIieTR02l4ERFUl07fgMYtqLgqDZZ0w7jW4MZBW7Nuy78tgQ11Jfgswn/slyZei09vcrqYKjBt7Np6lqAAihOzXzE2/zK874hrcKEKatayfBsbAuJg=", "urls": [ - "https://pixeldrain.com/api/file/6NjT6uEl", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_mac.dmg" + "https://pixeldrain.com/api/file/jEWmNDRX", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_mac.dmg" ] } }, "debian9": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "debian10": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "fedora28": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "fedora29": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "fedora30": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" + ] + } + }, + "fedora31": { + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", + "urls": [ + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "opensuse15": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "opensuse15.1": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "solus": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "tumbleweed": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "ubuntu18.04": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "ubuntu18.10": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "ubuntu19.04": { - "1.0.11": { - "sha256": "616342ec7a2fdd38dde36a24e650e7763a6150d27e67527a2ad76e55390a6d19", - "sig": "A1OUhRTqFPQ1I4V1/R6UAu+9+QH2VWQDnB/BdCcaZZcVy91MQDXxvE0QkKi+eVbXizL/eQDdrUMyKItVDX3W390c7f0xv5sdz/xYCP7J7ArVJoStdv82JE4NvqPH2NucWSsUx5Qpd4MNQbKuRBKzs/C4JA49htJffUTncgu06Q1IIn0DhpcQeQtivaIHTTgtf3mnoh7kIeXqKjh0SX5LtdTs6RmG6eylm02QYPTC0mtGEGoDfL7cduXSxrn/cy/o9JBPcXMUUfujBo+zuxlNNKhZezhEHJP6ZONmPNQk5eh/qdOkL3QL3et7bJfJlPx9IHwwglNyHwM3lSaYsCv8LlfdovxxX6DvtNOhA/sMx4KkC+Me7YwtLKT8zrx2twXHwCxMkGPcwLr4ODyYlg9Ru4U8cIkaFjv4ycaAeatBsOJTd1IZA8DdQQEkdCJsd77EiJrvNBWwvGWev3KQ5ZIxX68ceqhbe+KBuN9IpsvcS4yHbMPcqcRbhzDZWN/x0AyUE2o9PsL1SXZSxML/TctBAVwPRf/YeDEygxdREN7pUbGFiHuQAx0uGin1c8UGSpL0hEb6WtYVcCSR2RX/LTEJG8vwGBANZqKNeN96INepb6wMgen9JpB5ZCUpA+1H91pxrdgMttrhnLHvsvRB69tgpmlR3oIjk3Nb9M9lW9e3AY/qOBYlBwU7hAdEaUg09MWXLxaBrg3KQAlsW7I/eUckZmW1sy8ehk2shlEL4GgFBxi8vf++r/+9q2GfMhkHoNxkVqCo2tGV6zaJQyMIVS5Gi9u+gYrtCTSn20U1TJrLBoqFz6p45NP1PyomdE2zdVoDWP5M4NfTSJTc7bfRtIE835GTrf2u2BNmOQw7V7D9PmbJeBTYz6+MYoD9mEhfNQQICLm1X1vE0xiHyRYgoRfy9DYWQohJryOjwmuSXrx6EnCm3N7EsmcocU8Tmk6M/TKJqjmmuBUemoVf2dOOfM3/r7yPnMXaOA0lu4b9725CxqfehVNAsxkFckaB4+C4JJ/cdT+UVT2lEP4MRyueLh2WUEbjiN2kKyBUs9zREJ+nbNSf2QSDVJySMecBbw+hJbjbNhvmRy/THUsuVFUEoKQwnk+hT4QK8jVfV8qm+oWIsKbKqExJm3phdEY/YNN/WjxqSDo6aw8X0oBpzCkUcyB3Z9pIE1kf6Ke9V9NKVJHUioXH11oi2webBtxJQtMriIgwIms01s0SUMs/iOcq9q//S8VYQJlH8eBpmvOGeGPbkCJtmGEwExcyxAocUGr2tIjQH8ZbKMXnQuuS7HhmJiWYtZF0itvMr66CxfxpOM4A3z8GCq/4wOs3XJzD7dWdAZ1AjjIUCi1BXgotIBkGXJCXPVM=", + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", "urls": [ - "https://pixeldrain.com/api/file/cP4E5Aia", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.11_linux_x86_64.AppImage" + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" + ] + } + }, + "ubuntu19.10": { + "1.1.2": { + "sha256": "e6f8c32f6bc908da8d7a21b13a0d85365b53a24035838b3d40778a39a58395c0", + "sig": "AVtYwTJJ6w/AviQX6z4OGEls0Yv5AS2Q56t5u4TuEwCyIEgQVpy6tFxHRCrmjrrQQ34WlNmDlvrHghajZYAAf28uvIcTy9uKATPO1VgCYJvtTq2SnQF3rjXPcGQ/lCHN8bLh4w3yXVAUw36y/mKZMMV7j0OcHqcrYx1kmPuJDMtqrnHDASYYSaE071LL41dTaDjcizZfAdk8wM070R+Ea43ySR9eOIgnRKMq/mCD66/JinrLK9dWUfMC9ePhOn4u18rMJN0zjcDL6b446bd8Ojv3YdIjqQ38aR/YArOCye6bsv6tB5td+w/4ZXPpj3zcuTpaClkBagR8blfCnpeY9YS4W4BcOHYE3D8oZmQyv6DsSox+V07Jc2gZ253VHUUhcQbH0CQ+i0t3eAiNnJKKtQz5QeyFSgLB1et2dqQ9AMtjGTznYIO43xmsj02rtvEJR1up1OgYsSEpVfdABm6Ohf5nPr7566ECzHMCzfprrQ9YyjodmTD1TBw3dTA8SDWFdSfj2FjfPcpW1ZHumPfb+aVmfv5j3UYvqJFkqYYC+KS0jZjPcLh/UQIswKOEqkLHMnT5bzK8PilqJ+cabJ4lu+NvRra73NKlV/B/e8ItEoZFYJbRbTy0IaToujnaH/1TpOjFgvm+Fye0+pydMj9aPDiXKl/XrXPdTbT2driN7l4chNcUtDLdvn0bs8iTN9oEZtrsGXe5dP6Mtzp0yZCRCGxLPIwRUIaWl39hhzZ1a5pOYvSv32RJmA+GGGAn59kxJh/SU/1lOB6NKZVvKO/k14bjfMvNU6XbaIvYEN55WTtGgENhBAfYB6IyszU4y0sjASf2iifa/dzlUcXczhyhkHqZClGguoSo+H86i6At9i1rRmRfHsMLAZqW482EPbC055qodfK+v0+d4zl9hpVUaonb/9JOpYuDW9suLVhoILe0M4A5lnFNNmFbQPVVpeO7YDX9bkBeiMUyekYbQJYJ/eOxjfKWeK8g7fXJ7wGRyxgKfnXGwoYE1cfRWNoV2nlOUtv4GeoW0jcBAyqq0gM+5h/rn5/rFsNvDVACP0x/3wJoPoeKKtkNHYysgmnNaI0CbnM/KoxcNjd18KjK2Dw6o7YscZ0ZKjDpbNU9ZtI+X08XwLXQMAoLH+ipV4ugTapNXaLszp0ZZg1og0tuAIw5KExmcHMGcF3gARaUpOdTHYdN4q7Iht4j9joF6WmFUvLQal71kv7TGw8n00xpEIpp+sfeQuLUY5d/KyPMpf/D+8+RCOLQt7sc3n+28gO7doVl9VS2CT2Bkw7xXdstWdMSOd2dkXthvsLgK6san2snJYjvoy1T7aArtWqllQ1DMbTxmA/LxNn/HWnWkEi/4uCssUk=", + "urls": [ + "https://pixeldrain.com/api/file/5i1mA1gb", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_linux_x86_64.AppImage" ] } }, "win32": { - "1.0.10": { - "sha256": "62a7c36fd8657feda57134ebacac4feab65ebd577668a608770cbdf05a669055", - "sig": "A3t7jyMck0qrWLNAhFUxgNns/bEphbx3DzXcTnAc0g0z1l7JWBCk4MxNyovJCCGc5NmmAgK+U8KKbdGizqPaZrjggH6Sq4BjRSD/FGrX7c59G/rj1jD1y+A5aN3M77tz+2z+XVyUvtqRYN1Jh+JoBZOnHC4wywnOiu9Q942Ky4Ecn2wiNcyquHQailqR/rAVNVQ1qAWq5b54nySZs4ZuSF0uvgDYobWeYnMUSlU9p9u8ojPW0teqZKngNzexUynJQfZoBE0f4O5DUUDU4FDaWn3AcXdjnTLthPT2nJ8EXVCguod9MD9pjBfbr/UYUrSywG5bK01G3ZJLXs6dxb9xb2a9EoXPP91SDNZ3gAq+J+qKXUkN5kFCkC1Z+oyIClx08HQ0Pu24MCCSm4xYz1OAQygqCXCncmJEwvT+1qDPp8u8dobWO9lH+C4rRTUP/NHs78vCIQ0kR1r2k1q/1Xi1RalJ2N5V1nwPBRBH4iB/mQ5Z0CIYb/Wm8I5jexENWVEOWP1kTXCq9SGBDPuJYWIwrOz5UkgkZ0fQlOQaxI2ZWSTd5cUSQsljZoZ+T4pU2gMNR7T+GOjyc/hndx0w7D3gtzRy2/DVvMUmAnADCeIHfIivOtb9V1Uzu6Op84QKOv5rTe791QLplqcg620o6qIYr7lRA3tbSKrgR78XVGQA8odv79VtFh3PAGRkQ/nTkaucPBL9KmiB4KDctzLr49ky4d7xMOv68S72U69LBM886nA7vlQdEwIcW1TLkLj1n2DJADARu0Uub0M1O4PnQp/4iJic/dfWm0DIwvLltYNJrYT4G7m0KilzqcpPxhaUIkgDarcwWhisCAX9TvP9DhYQbjf0FDsp4KqhRvfn37QDI01DYRY80GSllabHf5sT0AxCgEGAPXC0BP+7OM8hjO/XXTExv4eXPlFoDI1+qLMRH+4GgnTCBks3Axe5rPhWzJZqqSLpWCNArQFhREwJqCyvdEtSyujM1bQ0nLawRlGbUJ9CJ/yQGGV92DiT3pyTaTNpLAATA9xKGuxiTMq1PGKRZTGPnGK5udvK11Vt7B8cmPpWQyixD98R989zkleuu5b/xDWXtRZcMm0ls0IZeX8/VTrhJEtYZsZ8k6UXJJ8UQJFRoQ2zlTCNGIt/9ZcslF9sfxJ7Bi1YeDJyeCykwR0RuTNunFsFKRrnDHoXxY9JihIOXNBJI9+iELqPdWwkNWtrelKciZN4edCxcg5UYF6kEGAJsrFUlYq2zfXwlxb4VQIHACTsiPsAuMGiyG3hydcFF2UGY8MKKxOeGnvyLInaJMfmQLY4iHoT2g8jBlfkgFvyHmSdM/KsJKxLxW4ve5x5QB8KX4gBVPZZW0GJxY/Tqz0=", + "1.1.2": { + "sha256": "2534a2aa350d4ed1786c4b1cd298ccc987fae226850a1a8bd6d54a8fac39295c", + "sig": "Azsov3SYmN/+I3ojIAtYubfEctxD+0QgtgmeubXnjMacb1us8Lu9hFb2wVVd7RGWtsHRmxkpWAi+hUd+gSjM9ahPbm164uq2licspNWeaGJFsQ6LDT6htKz0mQAyfZB9UrKCZrfFKDMXji85GqyUlGu92NlcnXK2tVxMFuB8DHKO+uG97+YisrwvoxLgVSM/9XrjfVEJMcik4URFF1tL5IRksnqA7ccuo++BmoDOcTFvRSky5tNl/KKabEJQLS72FIJI42djBKEn/tE9wxPhBUAa/ya5crOlkD+FgAywoUScbhwcGzg1EMjtDCIDEZrsmfW91jlZmJKDxTv8DaV2MFn97NZVWGWEjU9iOYzd0j4GbNtG58M6YM6ViCJ9fCjSCGrxLS76B9Ra2YShSaJJ6RbD7JiZI86btohiQBbguhvPq16BgRUi35SQCIerASYJTjCys958fSYGd66yfyQNOcFLaTzuvG5nSpbdsakLxAqRzYx+ATYY1lETWk5OMst0pkjIxFid+xw8+/btwlfrtrGx7R7WKAfQJAL/OxvXkhiOZ3aylcdnf8tspOsjUKDGHuznt6HQvdTreUDAVZL6iVL9h+QNEeTw1AISaVqy4+dtGwFGdIxacyt5az9rpnoI9w52cARQiiUyk3I5IGyBF20ia75QXoAOZcaPiBM4yF9gicG8VKW+XFO5FBQCZiktcrNZ0lB8USILjHfRSnITqEZCOKiMRBLQVdJuwa/QxkH3tQfmVFr1FN18ZiImnLITTr2ffiFhXoQTF9NQNGtLHKLe6xvPjPjQm0ZdBKKHw7y5jkkA2mQysvD10ebackP+SLPR7hq3uBhhQsBic4pVDV1GS3UsP/etExzWCwos11MpChRSG5fAmROMiLR1DkvPUJslM4A7Rm+weo91F8+48krxNYRKeJszCWBcRUJnEd5sYI83bJ0RM6+ftl+29YW8QJpVf1tJ0D22yaTI/XgGHusdQircD4vLRKPfkXn8XEApFnLV9knujzXs5vrlQNTFFarXG+f+7E6IeXE+jneaSBXru0XgYyFCy8HRqq5rgMu1SHU5UjdWQyBM1bNGXp8WOOwuDpVbTUHg16TJ99GMbvYNjL9sJNjFcsNcId7b2gNWxo60w9O8C4+GUJrexisjQCZFzL7d/PbKCvHZp1MpliNEEIV43rniY7KUcXUmvLnMrKywj1aYVTRpLDJrtjGEGZ7OeVrxKPR/wPIpV9DD05xyOpYNyamIs5uJyBoBESXUGM+6kWhc5ZO+EJvueVU7OvuqQG8l5YQAbZvLI03jgJLTCyWxvu0zdpsSUtH560zXumuVlbCqJj2XWizP+aCQbqSnvtv1hFxJYv7a9yIgvLc=", "urls": [ - "https://pixeldrain.com/api/file/YCzKB0a9", - "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.10_win.exe" + "https://pixeldrain.com/api/file/TkQn25Bm", + "https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.1.2_win.exe" ] } } }, "Versions": { "arch": [ - "1.0.11" + "1.1.2" ], "centos7": [ - "1.0.11" + "1.1.2" ], "darwin": [ - "1.0.8" + "1.1.2" ], "debian9": [ - "1.0.11" + "1.1.2" ], "debian10": [ - "1.0.11" + "1.1.2" ], "fedora28": [ - "1.0.11" + "1.1.2" ], "fedora29": [ - "1.0.11" + "1.1.2" ], "fedora30": [ - "1.0.11" + "1.1.2" + ], + "fedora31": [ + "1.1.2" ], "linux": [ "unavailable" ], "opensuse15": [ - "1.0.11" + "1.1.2" ], "opensuse15.1": [ - "1.0.11" + "1.1.2" ], "solus": [ - "1.0.11" + "1.1.2" ], "tumbleweed": [ - "1.0.11" + "1.1.2" ], "ubuntu18.04": [ - "1.0.11" + "1.1.2" ], "ubuntu18.10": [ - "1.0.11" + "1.1.2" ], "ubuntu19.04": [ - "1.0.11" + "1.1.2" + ], + "ubuntu19.10": [ + "1.1.2" ], "unknown": [ "unavailable" ], "win32": [ - "1.0.10" + "1.1.2" ] } } diff --git a/src/App.css b/src/App.css index 895aeba..876ccd7 100644 --- a/src/App.css +++ b/src/App.css @@ -1,18 +1,14 @@ .App { - display: flex; - flex-direction: column; margin: 0; - padding: 10px; + padding: var(--default_spacing); box-sizing: border-box; height: 100vh; width: 100vw; - background-image: url('./assets/images/background.jpg'); + background-image: url('./assets/images/background2.jpg'); background-size: cover; } .AppContainer { - display: flex; - flex-direction: column; width: 100%; height: 100%; box-sizing: border-box; @@ -20,11 +16,11 @@ .AppHeader { height: 28px; - margin-bottom: 8px; + margin-bottom: var(--default_spacing); box-sizing: border-box; } .AppContent { - flex: 1; + height: calc(100% - 36px); box-sizing: border-box; } \ No newline at end of file diff --git a/src/App.js b/src/App.js index 780b5e5..1c90f12 100644 --- a/src/App.js +++ b/src/App.js @@ -10,7 +10,6 @@ import Grid from './components/UI/Grid/Grid'; import InfoDetails from './components/InfoDetails/InfoDetails'; import IPCContainer from './containers/IPCContainer/IPCContainer'; import Loading from './components/UI/Loading/Loading'; -import Modal from './components/UI/Modal/Modal'; import MountItems from './containers/MountItems/MountItems'; import {notifyError} from './redux/actions/error_actions'; import Reboot from './components/Reboot/Reboot'; @@ -27,6 +26,8 @@ import { loadReleases, setDismissUIUpgrade } from './redux/actions/release_version_actions'; +import YesNo from './components/YesNo/YesNo'; +import {createModalConditionally} from './utils'; const Constants = require('./constants'); const Scheduler = require('node-schedule'); @@ -65,11 +66,6 @@ class App extends IPCContainer { super.componentWillUnmount(); } - createModalConditionally = (condition, jsx, critical) => { - const modalProps = {critical: critical}; - return condition ? ({jsx}) : null; - }; - getSelectedVersion = () => { return (this.props.ReleaseVersion === -1) ? 'unavailable' : @@ -102,6 +98,9 @@ class App extends IPCContainer { const noConsoleSupported = this.props.LocationsLookup[selectedVersion] && this.props.LocationsLookup[selectedVersion].no_console_supported; + const remoteSupported = this.props.LocationsLookup[selectedVersion] && + this.props.LocationsLookup[selectedVersion].supports_remote; + const showConfig = !missingDependencies && this.props.DisplayConfiguration && !this.props.RebootRequired && @@ -122,49 +121,48 @@ class App extends IPCContainer { !this.props.DismissDependencies && this.props.AllowMount; - const infoDisplay = this.createModalConditionally(this.props.DisplayInfo, , true); - const rebootDisplay = this.createModalConditionally(this.props.RebootRequired, ); - const configDisplay = this.createModalConditionally(showConfig, ); - const dependencyDisplay = this.createModalConditionally(showDependencies, ); - const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, ); - const errorDisplay = this.createModalConditionally(this.props.DisplayError, , true); - const upgradeDisplay = this.createModalConditionally(showUpgrade, ); - const selectAppPlatformDisplay = this.createModalConditionally(this.props.DisplaySelectAppPlatform, ); + const configDisplay = createModalConditionally(showConfig, ); + const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, ); + const dependencyDisplay = createModalConditionally(showDependencies, ); + const downloadDisplay = createModalConditionally(this.props.DownloadActive, ); + const errorDisplay = createModalConditionally(this.props.DisplayError, , true); + const infoDisplay = createModalConditionally(this.props.DisplayInfo, , true); + const rebootDisplay = createModalConditionally(this.props.RebootRequired, ); + const selectAppPlatformDisplay = createModalConditionally(this.props.DisplaySelectAppPlatform, ); + const upgradeDisplay = createModalConditionally(showUpgrade, ); let mainContent = []; if (this.props.DisplaySelectAppPlatform || !this.props.AppReady) { - mainContent = + mainContent = ( + + + ); } else { let key = 0; mainContent.push(( -
+ -
+ )); - + mainContent.push(
); if (allowMount) { mainContent.push(( -
+ -
+ noConsoleSupported={noConsoleSupported} + remoteSupported={remoteSupported}/> + )); } } return (
- {selectAppPlatformDisplay} - {dependencyDisplay} - {upgradeDisplay} - {configDisplay} - {infoDisplay} - {downloadDisplay} - {rebootDisplay} - {errorDisplay}
@@ -187,11 +185,18 @@ class App extends IPCContainer {
- - {mainContent} - + {mainContent}
+ {selectAppPlatformDisplay} + {dependencyDisplay} + {upgradeDisplay} + {configDisplay} + {infoDisplay} + {confirmDisplay} + {downloadDisplay} + {rebootDisplay} + {errorDisplay}
); } @@ -205,6 +210,7 @@ const mapStateToProps = state => { AppReady: state.common.AppReady, DismissDependencies: state.install.DismissDependencies, DisplayConfiguration: state.mounts.DisplayConfiguration, + DisplayConfirmYesNo: state.common.DisplayConfirmYesNo, DisplayError: state.error.DisplayError, DisplayInfo: state.error.DisplayInfo, DisplaySelectAppPlatform: state.common.DisplaySelectAppPlatform, diff --git a/src/assets/images/Connect_To_Remote.gif b/src/assets/images/Connect_To_Remote.gif new file mode 100644 index 0000000..2bf5d5e Binary files /dev/null and b/src/assets/images/Connect_To_Remote.gif differ diff --git a/src/assets/images/Enable_Remote_Mount.gif b/src/assets/images/Enable_Remote_Mount.gif new file mode 100644 index 0000000..eb6f3b3 Binary files /dev/null and b/src/assets/images/Enable_Remote_Mount.gif differ diff --git a/src/assets/images/background2.jpg b/src/assets/images/background2.jpg new file mode 100644 index 0000000..c900303 Binary files /dev/null and b/src/assets/images/background2.jpg differ diff --git a/src/assets/settings.json b/src/assets/settings.json index 2642db6..66affa1 100644 --- a/src/assets/settings.json +++ b/src/assets/settings.json @@ -1,10 +1,18 @@ { "HostConfig": { - "AgentString": "'User-Agent' used when communicating with Sia/SiaPrime's API.", - "ApiPassword": "Password used when communicating with Sia/SiaPrime's API.\n\nThis is not the same as your wallet's password, so please do not enter it here. Sia/SiaPrime typically auto-generate this value. It is exclusively used for API authentication purposes.", - "ApiPort": "API port used to connect to Sia/SiaPrime's daemon.", - "HostNameOrIp": "IP address or host name of Sia/SiaPrime daemon.", - "TimeoutMs": "Number of milliseconds to wait for Sia/SiaPrime API responses before timing out." + "AgentString": "'User-Agent' used when communicating with Sia/ScPrime's API.", + "ApiPassword": "Password used when communicating with Sia/ScPrime's API.\n\nThis is not the same as your wallet's password, so please do not enter it here. Sia/ScPrime typically auto-generate this value. It is exclusively used for API authentication purposes.", + "ApiPort": "API port used to connect to Sia/ScPrime's daemon.", + "HostNameOrIp": "IP address or host name of Sia/ScPrime daemon.", + "TimeoutMs": "Number of milliseconds to wait for Sia/ScPrime API responses before timing out." + }, + "RemoteMount": { + "EnableRemoteMount": "Allow mounting this location over TCP.", + "RemoteClientPoolSize": "Number of threads to use for each unique client.", + "RemoteHostNameOrIp": "Host name or IP of host to connect to for remote mounting.", + "RemoteMaxConnections": "Maximum number of TCP connections to use when communicating with remote instances.", + "RemotePort": "TCP port used for remote mounting.", + "RemoteToken": "Encryption token used for remote mounts. This value must be the same on local and remote systems." }, "Settings": { "ApiAuth": "Password used to communicate with Repertory's API. Auto-generated by default.", @@ -20,9 +28,9 @@ "EvictionDelayMinutes": "Number of minutes to wait after all file handles are closed before allowing file to be evicted from cache.", "MaxCacheSizeBytes": "This value specifies the maximum amount of local space to consume before files are removed from cache. EnableMaxCacheSize must also be set to true for this value to take affect.", "MinimumRedundancy": "Files are elected for removal once this value has been reached. Be aware that this value cannot be set to less than 1.5x.", - "OnlineCheckRetrySeconds": "Number of seconds to wait for Sia/SiaPrime daemon to become available/connectable.", + "OnlineCheckRetrySeconds": "Number of seconds to wait for Sia/ScPrime daemon to become available/connectable.", "OrphanedFileRetentionDays": "Repertory attempts to keep modifications between Sia-UI and the mounted location in sync as much as possible. In the event a file is removed from Sia-UI, it will be marked as orphaned in Repertory and moved into an 'orphaned' directory within Repertory's data directory. This setting specifies the number of days this file is retained before final deletion.", - "PreferredDownloadType": "Repertory supports 3 download modes for reading files that are not cached locally: full file allocation, ring buffer mode and direct mode.\n\nFull file allocation mode pre-allocates the entire file prior to downloading. This mode is required for writes but also ensures the best performance when reading data.\n\nRing buffer mode utilizes a fixed size file buffer to enable a reasonable amount of seeking. This alleviates the need to fully allocate a file. By default, it is 512MiB. When the buffer is full, it attempts to maintain the ability to seek 50% ahead or behind the current read location without the need to re-download data from Sia/SiaPrime.\n\nDirect mode utilizes no disk space. All data is read directly from Sia/SiaPrime.\n\nPreferred download type modes are:\n\nFallback - If there isn't enough local space to allocate the full file, ring buffer mode is used. If there isn't enough local space to create the ring buffer's file, then direct mode is used.\nRingBuffer - Full file allocation is always bypassed; however, if there isn't enough space to create the ring buffer's file, then direct mode will be chosen.\nDirect - All files will be read directly from Sia/SiaPrime.", + "PreferredDownloadType": "Repertory supports 3 download modes for reading files that are not cached locally: full file allocation, ring buffer mode and direct mode.\n\nFull file allocation mode pre-allocates the entire file prior to downloading. This mode is required for writes but also ensures the best performance when reading data.\n\nRing buffer mode utilizes a fixed size file buffer to enable a reasonable amount of seeking. This alleviates the need to fully allocate a file. By default, it is 512MiB. When the buffer is full, it attempts to maintain the ability to seek 50% ahead or behind the current read location without the need to re-download data from Sia/ScPrime.\n\nDirect mode utilizes no disk space. All data is read directly from Sia/ScPrime.\n\nPreferred download type modes are:\n\nFallback - If there isn't enough local space to allocate the full file, ring buffer mode is used. If there isn't enough local space to create the ring buffer's file, then direct mode is used.\nRingBuffer - Full file allocation is always bypassed; however, if there isn't enough space to create the ring buffer's file, then direct mode will be chosen.\nDirect - All files will be read directly from Sia/ScPrime.", "ReadAheadCount": "This value specifies the number of read-ahead chunks to use when downloading a file. This is a per-open file setting and will result in the creation of an equal number of threads.", "RingBufferFileSize": "The size of the ring buffer file in MiB. Default is 512. Valid values are: 64, 128, 256, 512, 1024." } diff --git a/src/components/ConfigurationItem/ConfigurationItem.css b/src/components/ConfigurationItem/ConfigurationItem.css deleted file mode 100644 index 328ae2c..0000000 --- a/src/components/ConfigurationItem/ConfigurationItem.css +++ /dev/null @@ -1,40 +0,0 @@ -.ConfigurationItem { - margin: 0; - padding: 0; -} - -input.ConfigurationItemInput { - display: block; - margin: 0; - padding: 2px; - border-radius: var(--border_radius); - background: rgba(160, 160, 160, 0.1); - border: none; - box-shadow: none; - outline: none; - color: var(--text_color); - box-sizing: border-box; -} - -.ConfigurationItemSelect { - display: block; - margin: 0; - padding: 2px; - border-radius: var(--border_radius); - background: rgba(160, 160, 160, 0.1); - border: none; - box-shadow: none; - outline: none; - color: var(--text_color); - box-sizing: border-box; -} - -.ConfigurationItemOption { - background: rgba(10, 10, 15, 0.8); - border-color: rgba(10, 10, 20, 0.9); - color: var(--text_color); -} - -.ConfigurationInfo { - cursor: pointer; -} \ No newline at end of file diff --git a/src/components/ErrorDetails/ErrorDetails.css b/src/components/ErrorDetails/ErrorDetails.css index 0c6efbd..338b0ed 100644 --- a/src/components/ErrorDetails/ErrorDetails.css +++ b/src/components/ErrorDetails/ErrorDetails.css @@ -7,5 +7,5 @@ .ErrorDetailsContent { max-height: 60vh; overflow-y: auto; - margin-bottom: 8px; + margin-bottom: var(--default_spacing); } \ No newline at end of file diff --git a/src/components/ErrorDetails/ErrorDetails.js b/src/components/ErrorDetails/ErrorDetails.js index a0894b6..409efb8 100644 --- a/src/components/ErrorDetails/ErrorDetails.js +++ b/src/components/ErrorDetails/ErrorDetails.js @@ -19,7 +19,7 @@ const mapDispatchToProps = dispatch => { export default connect(mapStateToProps, mapDispatchToProps)(props => { return ( - +

Application Error

{props.ErrorMessage}

diff --git a/src/components/InfoDetails/InfoDetails.css b/src/components/InfoDetails/InfoDetails.css index ae9a3ae..5034a36 100644 --- a/src/components/InfoDetails/InfoDetails.css +++ b/src/components/InfoDetails/InfoDetails.css @@ -7,5 +7,5 @@ max-height: 60vh; min-width: 80vw; overflow-y: auto; - margin-bottom: 8px; + margin-bottom: var(--default_spacing); } \ No newline at end of file diff --git a/src/components/InfoDetails/InfoDetails.js b/src/components/InfoDetails/InfoDetails.js index 2bbcc7e..afc6f04 100644 --- a/src/components/InfoDetails/InfoDetails.js +++ b/src/components/InfoDetails/InfoDetails.js @@ -19,7 +19,7 @@ const mapDispatchToProps = dispatch => { export default connect(mapStateToProps, mapDispatchToProps)(props => { return ( - +

{props.InfoMessage.title}

{props.InfoMessage.message}

diff --git a/src/components/Reboot/Reboot.css b/src/components/Reboot/Reboot.css index 26160e5..3ba26f7 100644 --- a/src/components/Reboot/Reboot.css +++ b/src/components/Reboot/Reboot.css @@ -7,5 +7,5 @@ .RebootContent { max-height: 60vh; overflow-y: auto; - margin-bottom: 8px; + margin-bottom: var(--default_spacing); } \ No newline at end of file diff --git a/src/components/Reboot/Reboot.js b/src/components/Reboot/Reboot.js index 242a3e9..4700cdf 100644 --- a/src/components/Reboot/Reboot.js +++ b/src/components/Reboot/Reboot.js @@ -13,7 +13,7 @@ const mapDispatchToProps = dispatch => { export default connect(null, mapDispatchToProps)(props => { return ( - +

Reboot System

Repertory requires a system reboot to continue.

diff --git a/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js b/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js index 9106a18..71dadfe 100644 --- a/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js +++ b/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js @@ -41,13 +41,14 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { }; const handleReleaseChanged = e => { - const release = parseInt(e.target.value, 10); + const release = Constants.RELEASE_TYPES.indexOf(e.target.value); const releaseVersion = props.VersionLookup[Constants.RELEASE_TYPES[release]].length - 1; props.setActiveRelease(release, releaseVersion); }; const handleVersionChanged = e => { - props.setActiveRelease(props.Release, parseInt(e.target.value, 10)); + const releaseVersion = props.VersionLookup[Constants.RELEASE_TYPES[props.Release]].indexOf(e.target.value); + props.setActiveRelease(props.Release, releaseVersion); }; const text = props.InstalledVersion + ' [' + props.AppPlatform + ']'; @@ -107,7 +108,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { } return ( - + columns / 3} rowSpan={4} text={'Release'} @@ -119,7 +120,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { items={Constants.RELEASE_TYPES} row={5} rowSpan={7} - selected={props.Release}/> + selected={Constants.RELEASE_TYPES[props.Release]}/> dimensions.columns / 3} colSpan={remain=>remain / 2} rowSpan={4} @@ -138,7 +139,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { items={props.VersionLookup[Constants.RELEASE_TYPES[props.Release]]} row={5} rowSpan={7} - selected={props.ReleaseVersion}/> + selected={props.VersionLookup[Constants.RELEASE_TYPES[props.Release]][props.ReleaseVersion]}/> {optionsDisplay} ); diff --git a/src/components/UI/CheckBox/CheckBox.css b/src/components/UI/CheckBox/CheckBox.css new file mode 100644 index 0000000..1498bad --- /dev/null +++ b/src/components/UI/CheckBox/CheckBox.css @@ -0,0 +1,76 @@ +.CheckBoxOwner { + display: block; + width: 100%; + height: 100%; + margin: 0; + padding: 0; +} + +/* Customize the label (the container) */ +label.CheckBoxLabel { + position: relative; + padding-left: 24px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* Hide the browser's default checkbox */ +label.CheckBoxLabel input[type=checkbox] { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; +} + +/* Create a custom checkbox */ +.CheckBoxCheckMark { + display: block; + margin: 0; + border-radius: var(--border_radius); + background-color: var(--control_background); + box-sizing: border-box; + position: absolute; + top: 0; + left: 0; + height: 20px; + width: 20px; +} + +/* On mouse-over, add a grey background color */ +label.CheckBoxLabel:hover input[type=checkbox] ~ .CheckBoxCheckMark { + background-color: var(--control_background_hover); +} + +/* When the checkbox is checked, add a blue background */ +label.CheckBoxLabel input:checked ~ .CheckBoxCheckMark { + background-color: var(--control_background); +} + +/* Create the CheckBoxCheckMark/indicator (hidden when not checked) */ +.CheckBoxCheckMark:after { + content: ""; + position: absolute; + display: none; +} + +/* Show the CheckBoxCheckMark when checked */ +label.CheckBoxLabel input:checked ~ .CheckBoxCheckMark:after { + display: block; +} + +/* Style the CheckBoxCheckMark/indicator */ +label.CheckBoxLabel .CheckBoxCheckMark:after { + left: 6px; + top: 1px; + width: 5px; + height: 10px; + border: solid var(--heading_text_color); + border-width: 0 3px 3px 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} \ No newline at end of file diff --git a/src/components/UI/CheckBox/CheckBox.js b/src/components/UI/CheckBox/CheckBox.js new file mode 100644 index 0000000..adc0e04 --- /dev/null +++ b/src/components/UI/CheckBox/CheckBox.js @@ -0,0 +1,16 @@ +import React from 'react'; +import './CheckBox.css'; + +export default props => { + return ( +
+ +
+ ); +}; \ No newline at end of file diff --git a/src/components/UI/DropDown/DropDown.css b/src/components/UI/DropDown/DropDown.css index a1408b9..5c7b489 100644 --- a/src/components/UI/DropDown/DropDown.css +++ b/src/components/UI/DropDown/DropDown.css @@ -19,6 +19,24 @@ box-sizing: border-box; } +.DropDownSelect.Alt { + width: 100%; + height: 100%; + display: block; + margin: 0; + padding: 2px; + border-radius: var(--border_radius); + background: rgba(160, 160, 160, 0.1); + border: none; + color: var(--text_color); + box-sizing: border-box; +} + +.DropDownSelect.Auto { + width: auto; + height: auto; +} + .DropDownOption { background: rgba(10, 10, 15, 0.9); border-color: rgba(10, 10, 20, 0.9); diff --git a/src/components/UI/DropDown/DropDown.js b/src/components/UI/DropDown/DropDown.js index cc25550..f19cc1d 100644 --- a/src/components/UI/DropDown/DropDown.js +++ b/src/components/UI/DropDown/DropDown.js @@ -4,13 +4,16 @@ import './DropDown.css'; export default props => { const options = props.items.map((s, i) => { return ( - + ); }); return (
- {options}
diff --git a/src/components/UI/Grid/Grid.js b/src/components/UI/Grid/Grid.js index 3eec900..4aac1f3 100644 --- a/src/components/UI/Grid/Grid.js +++ b/src/components/UI/Grid/Grid.js @@ -2,17 +2,10 @@ import React, {Component} from 'react'; import './Grid.css'; import GridComponent from './GridComponent/GridComponent'; +const DEFAULT_GRID_SIZE = 4; + export default class extends Component { - constructor(props) { - super(props); - window.addEventListener("resize", this.updateSizeAsync); - this.checkSizeInterval = setInterval(()=> { - this.updateSize() - }, 2000); - } - - checkSizeInterval; - + resizeTimeout; state = { calculated: false, dimensions: { @@ -21,21 +14,44 @@ export default class extends Component { } }; - calculateDimensions = (size) => { + calculateDimensions = size => { return { - columns: Math.floor(size.width / 4), - rows: Math.floor(size.height / 4) + columns: Math.floor(size.width / this.getGridSize()), + rows: Math.floor(size.height / this.getGridSize()) }; }; + componentDidMount() { + window.addEventListener('resize', this.handleResize); + this.updateSizeAsync(); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.handleResize); + clearInterval(this.resizeTimeout); + }; + + getGridSize = () => { + return this.props.gridSize || DEFAULT_GRID_SIZE; + }; + + getGridSizePx = () => { + return this.getGridSize() + 'px '; + }; + getSize = () => { const elem = this.refs.GridOwner; return { - height: elem ? elem.clientHeight : 0, - width: elem ? elem.clientWidth : 0 + height: elem ? elem.offsetHeight : 0, + width: elem ? elem.offsetWidth : 0 }; }; + handleResize = () => { + clearTimeout(this.resizeTimeout); + this.resizeTimeout = setTimeout(this.updateSizeAsync, 10); + }; + updateSize = () => { const state = { ...this.state @@ -51,21 +67,11 @@ export default class extends Component { }; updateSizeAsync = () => { - return new Promise((done) => { + return new Promise(() => { this.updateSize(); - done(); }); }; - componentDidMount() { - this.updateSizeAsync(); - } - - componentWillUnmount() { - window.removeEventListener("resize", this.updateSizeAsync); - clearInterval(this.checkSizeInterval); - }; - render() { let children = null; const dimensions = this.state.dimensions; @@ -95,28 +101,36 @@ export default class extends Component { rowSpan = rowSpan ? (rowSpan === 'remain' ? (dimensions.rows - row) : rowSpan) : null; colSpan = colSpan ? (colSpan === 'remain' ? dimensions.columns - col : colSpan) : null; - return {child}; + return ( + + {child} + + ); } else { return null; } - }) - .filter(i => i !== null); + }); } - const style = { + const gridSizePx = this.getGridSizePx(); + let style = { style: { - gridTemplateColumns: '4px '.repeat(dimensions.columns).trim(), - gridTemplateRows: '4px '.repeat(dimensions.rows).trim(), - gridAutoColumns: '4px', - gridAutoRows: '4px' + gridTemplateColumns: gridSizePx.repeat(dimensions.columns), + gridTemplateRows: gridSizePx.repeat(dimensions.rows), + gridAutoColumns: gridSizePx, + gridAutoRows: gridSizePx, } }; + if (this.props.noScroll) { + style['style'].overflowX = 'visible'; + style['style'].overflowY = 'visible'; + } + return (
) - }; + } }; \ No newline at end of file diff --git a/src/components/UI/Loading/Loading.js b/src/components/UI/Loading/Loading.js index 4e3e95c..83c68d1 100644 --- a/src/components/UI/Loading/Loading.js +++ b/src/components/UI/Loading/Loading.js @@ -8,8 +8,8 @@ export default props => { className={'Loading'}>
); diff --git a/src/hoc/RootElem/RootElem.js b/src/components/UI/RootElem/RootElem.js similarity index 100% rename from src/hoc/RootElem/RootElem.js rename to src/components/UI/RootElem/RootElem.js diff --git a/src/components/YesNo/YesNo.css b/src/components/YesNo/YesNo.css new file mode 100644 index 0000000..e69de29 diff --git a/src/components/YesNo/YesNo.js b/src/components/YesNo/YesNo.js new file mode 100644 index 0000000..444ee4a --- /dev/null +++ b/src/components/YesNo/YesNo.js @@ -0,0 +1,41 @@ +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'; + +const mapStateToProps = state => { + return { + Title: state.common.ConfirmTitle, + } +}; + +const mapDispatchToProps = dispatch => { + return { + hideConfirmYesNo: confirmed => dispatch(hideConfirmYesNo(confirmed)), + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(props => { + return ( + +
+

{props.Title}

+
+ + + + + + + +
+ + + +
+
); +}); \ No newline at end of file diff --git a/src/constants.js b/src/constants.js index 7582f13..a2d90ab 100644 --- a/src/constants.js +++ b/src/constants.js @@ -27,11 +27,10 @@ exports.DEV_PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----\n' + '9wIDAQAB\n' + '-----END PUBLIC KEY-----'; - const REPERTORY_BRANCH = 'master'; const REPERTORY_UI_BRANCH = 'master'; -exports.RELEASES_URL = 'https://bitbucket.org/blockstorage/repertory/raw/' + REPERTORY_BRANCH + '/releases.json'; +exports.RELEASES_URL = 'https://bitbucket.org/blockstorage/repertory/raw/' + REPERTORY_BRANCH + '/releases_1.1.json'; exports.UI_RELEASES_URL = 'https://bitbucket.org/blockstorage/repertory-ui/raw/' + REPERTORY_UI_BRANCH + '/releases.json'; exports.LINUX_DETECT_SCRIPT_URL = 'https://bitbucket.org/blockstorage/repertory/raw/' + REPERTORY_BRANCH + '/detect_linux.sh'; @@ -39,7 +38,8 @@ exports.LINUX_DETECT_SCRIPT_URL = 'https://bitbucket.org/blockstorage/repertory/ exports.LINUX_SELECTABLE_PLATFORMS = [ 'ubuntu18.04', 'ubuntu18.10', - 'ubuntu19.04' + 'ubuntu19.04', + 'ubuntu19.10' ]; exports.DATA_LOCATIONS = { @@ -50,12 +50,12 @@ exports.DATA_LOCATIONS = { exports.PROVIDER_LIST = [ 'Sia', - 'SiaPrime' + 'ScPrime' ]; exports.PROVIDER_ARG = { sia: '', - siaprime: '-sp' + scprime: '-sp' }; exports.RELEASE_TYPES = [ @@ -87,8 +87,8 @@ exports.IPC_Check_Mount_Location = 'check_mount_location'; exports.IPC_Delete_File = 'delete_file'; -exports.IPC_Detect_Mounts = 'detect_mounts'; -exports.IPC_Detect_Mounts_Reply = 'detect_mounts_reply'; +exports.IPC_Detect_Mount = 'detect_mount'; +exports.IPC_Detect_Mount_Reply = 'detect_mount_reply'; exports.IPC_Download_File = 'download_file'; exports.IPC_Download_File_Complete = 'download_file_complete'; @@ -118,6 +118,9 @@ exports.IPC_Install_Upgrade_Reply = 'install_upgrade_reply'; exports.IPC_Mount_Drive = 'mount_drive'; exports.IPC_Mount_Drive_Reply = 'mount_drive_reply'; +exports.IPC_Remove_Remote_Mount = 'remove_remote_mount'; +exports.IPC_Remove_Remote_Mount_Reply = 'remove_remote_mount_reply'; + exports.IPC_Reboot_System = 'reboot_system'; exports.IPC_Save_State = 'save_state'; @@ -138,4 +141,4 @@ exports.IPC_Unmount_All_Drives = 'unmount_all'; exports.IPC_Unmount_All_Drives_Reply = 'unmount_all_reply'; exports.IPC_Unmount_Drive = 'unmount_drive'; -exports.IPC_Unmount_Drive_Reply = 'unmount_drive_reply'; \ No newline at end of file +exports.IPC_Unmount_Drive_Reply = 'unmount_drive_reply'; diff --git a/src/containers/AddRemoteMount/AddRemoteMount.css b/src/containers/AddRemoteMount/AddRemoteMount.css new file mode 100644 index 0000000..5a01963 --- /dev/null +++ b/src/containers/AddRemoteMount/AddRemoteMount.css @@ -0,0 +1,4 @@ +.AddRemoteMount { + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/src/containers/AddRemoteMount/AddRemoteMount.js b/src/containers/AddRemoteMount/AddRemoteMount.js new file mode 100644 index 0000000..52a8a00 --- /dev/null +++ b/src/containers/AddRemoteMount/AddRemoteMount.js @@ -0,0 +1,117 @@ +import React from 'react'; +import {Component} from 'react'; +import './AddRemoteMount.css'; +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} from '../../redux/actions/mount_actions'; +import {createModalConditionally} from '../../utils'; + +const mapStateToProps = state => { + return { + RemoteMounts: state.mounts.RemoteMounts, + }; +}; + +const mapDispatchToProps = dispatch => { + return { + addRemoteMount: (hostNameOrIp, port, token) => dispatch(addRemoteMount(hostNameOrIp, port, token)), + notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)), + } +}; + +export default connect(mapStateToProps, mapDispatchToProps)(class extends Component { + state = { + Display: false, + HostNameOrIp: '', + Port: 20000, + Token: '', + }; + + 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'); + } else { + this.setState({ + Display: false + }, () => { + this.props.addRemoteMount(this.state.HostNameOrIp, this.state.Port, this.state.Token); + this.setState({ + HostNameOrIp: '', + Port: 20000, + Token: '', + }); + }); + } + } + }; + + handleAddRemoteMount = () => { + this.setState({ + Display: true, + }); + }; + + render() { + const displayAdd = createModalConditionally(this.state.Display, ( + +

Add Remote Mount

+ + this.setState({HostNameOrIp: e.target.value.trim()})} + className={'ConfigurationItemInput'} + type={'text'} + value={this.state.HostNameOrIp}/> +
+ + this.setState({Port: e.target.value})} + className={'ConfigurationItemInput'} + type={'number'} + value={this.state.Port}/> +
+ + this.setState({Token: e.target.value})} + className={'ConfigurationItemInput'} + type={'text'} + value={this.state.Token}/> +
+ + + + + + + +
+ + + +
+ + )); + + return ( +
+ {displayAdd} + +
+ ); + } +}); \ No newline at end of file diff --git a/src/containers/Configuration/Configuration.css b/src/containers/Configuration/Configuration.css index 675f8c8..f29a322 100644 --- a/src/containers/Configuration/Configuration.css +++ b/src/containers/Configuration/Configuration.css @@ -1,6 +1,6 @@ .Configuration { - width: 90vw; - height: 90vh; - padding: 4px; + width: calc(100vw - (var(--default_spacing) * 4)); + height: calc(100vh - (var(--default_spacing) * 4)); + padding: var(--default_spacing); margin: 0; } \ No newline at end of file diff --git a/src/containers/Configuration/Configuration.js b/src/containers/Configuration/Configuration.js index f62cefd..30b1239 100644 --- a/src/containers/Configuration/Configuration.js +++ b/src/containers/Configuration/Configuration.js @@ -3,7 +3,7 @@ import './Configuration.css'; import {connect} from 'react-redux'; import Box from '../../components/UI/Box/Box'; import Button from '../../components/UI/Button/Button'; -import ConfigurationItem from '../../components/ConfigurationItem/ConfigurationItem'; +import ConfigurationItem from './ConfigurationItem/ConfigurationItem'; import Modal from '../../components/UI/Modal/Modal'; import IPCContainer from '../IPCContainer/IPCContainer'; import {displayConfiguration} from '../../redux/actions/mount_actions'; @@ -20,6 +20,7 @@ class Configuration extends IPCContainer { ObjectLookup: {}, OriginalItemList: [], OriginalObjectLookup: {}, + IsRemoteMount: false, ItemList: [], Saving: false, ShowAdvanced: false, @@ -70,6 +71,7 @@ class Configuration extends IPCContainer { 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, Version: this.props.version, }); } @@ -86,8 +88,12 @@ class Configuration extends IPCContainer { .map(key => { return { advanced: template[key] ? template[key].advanced : false, + hide_remote: template[key] ? template[key].hide_remote : false, label: key, - value: config[key], + remote: template[key] ? template[key].remote : false, + value: (template[key] && (template[key].type === 'object')) ? + config[key] : + config[key].toString(), }; }) .filter(i=> { @@ -98,7 +104,6 @@ class Configuration extends IPCContainer { } return ret; }); - return { ObjectList: objectList, ItemList: itemList, @@ -140,9 +145,20 @@ class Configuration extends IPCContainer { const list2 = this.createItemList(obj.value, this.state.Template[obj.label].template); objectLookup[obj.label] = list2.ItemList; } - const objectLookupCopy = JSON.parse(JSON.stringify(objectLookup)); + 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) { + delete objectLookup[obj.label]; + } + } + } + + const objectLookupCopy = JSON.parse(JSON.stringify(objectLookup)); this.setState({ + IsRemoteMount: isRemoteMount, ItemList: list.ItemList, ObjectLookup: objectLookup, OriginalItemList: itemListCopy, @@ -160,6 +176,7 @@ class Configuration extends IPCContainer { }, ()=> { this.sendRequest(Constants.IPC_Get_Config, { Provider: this.props.DisplayConfiguration, + Remote: this.props.DisplayRemoteConfiguration, Version: this.props.version, }); }); @@ -202,17 +219,37 @@ class Configuration extends IPCContainer { this.sendRequest(Constants.IPC_Set_Config_Values, { Items: changedItems, Provider: this.props.DisplayConfiguration, + Remote: this.props.DisplayRemoteConfiguration, Version: this.props.version, }); }); }; + showRemoteConfigItem = (item, itemList) => { + 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 === '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) { confirmSave = ( - +

Save Changes?

@@ -228,7 +265,7 @@ class Configuration extends IPCContainer { const configurationItems = this.state.ItemList .map((k, i) => { return ( - ((this.state.ShowAdvanced && k.advanced) || !k.advanced) ? + ((!this.state.IsRemoteMount || !k.hide_remote) && (!k.advanced || (this.state.ShowAdvanced && k.advanced))) ? this.handleItemChanged(e, i)} grouping={'Settings'} @@ -249,13 +286,14 @@ class Configuration extends IPCContainer { { this.state.ObjectLookup[key].map((k, i) => { return ( - ((this.state.ShowAdvanced && k.advanced) || !k.advanced) ? + (!k.advanced || (this.state.ShowAdvanced && k.advanced && !k.remote) || this.showRemoteConfigItem(k, this.state.ObjectLookup[key])) ? 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) @@ -269,12 +307,15 @@ class Configuration extends IPCContainer { return (
{confirmSave} - +
X
-

{this.props.DisplayConfiguration + ' Configuration'}

+

{( + this.props.DisplayRemoteConfiguration ? + this.props.DisplayConfiguration.substr(6) : + this.props.DisplayConfiguration) + ' Configuration'}

{objectItems} {(configurationItems.length > 0) ?

Settings

: null} @@ -289,13 +330,15 @@ class Configuration extends IPCContainer { const mapStateToProps = state => { return { DisplayConfiguration: state.mounts.DisplayConfiguration, + DisplayRemoteConfiguration: state.mounts.DisplayRemoteConfiguration, + Platform: state.common.Platform, } }; const mapDispatchToProps = dispatch => { return { notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)), - hideConfiguration: () => dispatch(displayConfiguration(null)), + hideConfiguration: () => dispatch(displayConfiguration(null, false)), } }; diff --git a/src/containers/Configuration/ConfigurationItem/ConfigurationItem.css b/src/containers/Configuration/ConfigurationItem/ConfigurationItem.css new file mode 100644 index 0000000..d170a37 --- /dev/null +++ b/src/containers/Configuration/ConfigurationItem/ConfigurationItem.css @@ -0,0 +1,21 @@ +.ConfigurationItem { + margin: 0; + padding: 0; +} + +input.ConfigurationItemInput { + display: block; + margin: 0; + padding: 2px; + border-radius: var(--border_radius); + background: rgba(160, 160, 160, 0.1); + border: none; + box-shadow: none; + outline: none; + color: var(--text_color); + box-sizing: border-box; +} + +.ConfigurationInfo { + cursor: pointer; +} \ No newline at end of file diff --git a/src/components/ConfigurationItem/ConfigurationItem.js b/src/containers/Configuration/ConfigurationItem/ConfigurationItem.js similarity index 78% rename from src/components/ConfigurationItem/ConfigurationItem.js rename to src/containers/Configuration/ConfigurationItem/ConfigurationItem.js index f143839..5a4d08a 100644 --- a/src/components/ConfigurationItem/ConfigurationItem.js +++ b/src/containers/Configuration/ConfigurationItem/ConfigurationItem.js @@ -1,10 +1,12 @@ import React from 'react'; import './ConfigurationItem.css'; -import settings from '../../assets/settings'; -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; -import {faInfoCircle} from '@fortawesome/free-solid-svg-icons'; +import CheckBox from '../../../components/UI/CheckBox/CheckBox'; import {connect} from 'react-redux'; -import {notifyInfo} from '../../redux/actions/error_actions'; +import {faInfoCircle} from '@fortawesome/free-solid-svg-icons'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {notifyInfo} from '../../../redux/actions/error_actions'; +import settings from '../../../assets/settings'; +import DropDown from '../../../components/UI/DropDown/DropDown'; const mapDispatchToProps = dispatch => { return { @@ -36,13 +38,14 @@ export default connect(null, mapDispatchToProps)(props => { let data; switch (props.template.type) { case "bool": - data = handleChanged(e)} - type={'checkbox'}/>; + data = ; break; case "double": data = handleChanged(e)} step={"0.01"} className={'ConfigurationItemInput'} @@ -51,24 +54,18 @@ export default connect(null, mapDispatchToProps)(props => { break; case "list": - const options = props.items.map((s, i) => { - return ( - - ); - }); - - data = ( - - ); + data = ; break; case "string": data = handleChanged(e)} className={'ConfigurationItemInput'} + disabled={props.readOnly} type={'text'} value={props.value}/>; break; @@ -76,6 +73,7 @@ export default connect(null, mapDispatchToProps)(props => { case "uint8": data = handleChanged(e)} className={'ConfigurationItemInput'} type={'number'} @@ -85,6 +83,7 @@ export default connect(null, mapDispatchToProps)(props => { case "uint16": data = handleChanged(e)} className={'ConfigurationItemInput'} type={'number'} @@ -94,6 +93,7 @@ export default connect(null, mapDispatchToProps)(props => { case "uint32": data = handleChanged(e)} className={'ConfigurationItemInput'} type={'number'} @@ -103,6 +103,7 @@ export default connect(null, mapDispatchToProps)(props => { case "uint64": data = handleChanged(e)} className={'ConfigurationItemInput'} type={'number'} diff --git a/src/components/MountItem/MountItem.css b/src/containers/MountItems/MountItem/MountItem.css similarity index 76% rename from src/components/MountItem/MountItem.css rename to src/containers/MountItems/MountItem/MountItem.css index 98470e8..c1c4e26 100644 --- a/src/components/MountItem/MountItem.css +++ b/src/containers/MountItems/MountItem/MountItem.css @@ -1,3 +1,10 @@ +.MountItem { + padding: 0; + margin: 0; + height: 56px; + overflow: visible; +} + input.MountItemInput { margin: 0; padding: 4px; diff --git a/src/components/MountItem/MountItem.js b/src/containers/MountItems/MountItem/MountItem.js similarity index 58% rename from src/components/MountItem/MountItem.js rename to src/containers/MountItems/MountItem/MountItem.js index e89d0f8..b56ae7e 100644 --- a/src/components/MountItem/MountItem.js +++ b/src/containers/MountItems/MountItem/MountItem.js @@ -1,14 +1,17 @@ import React from 'react'; import './MountItem.css'; import {connect} from 'react-redux'; -import DropDown from '../UI/DropDown/DropDown'; -import Button from '../UI/Button/Button'; +import DropDown from '../../../components/UI/DropDown/DropDown'; +import Button from '../../../components/UI/Button/Button'; import Loader from 'react-loader-spinner'; -import Text from '../UI/Text/Text'; -import Grid from '../UI/Grid/Grid'; -import configureImage from '../../assets/images/configure.png'; -import RootElem from '../../hoc/RootElem/RootElem'; -import {displayConfiguration, setProviderState} from '../../redux/actions/mount_actions'; +import Text from '../../../components/UI/Text/Text'; +import Grid from '../../../components/UI/Grid/Grid'; +import configureImage from '../../../assets/images/configure.png'; +import RootElem from '../../../components/UI/RootElem/RootElem'; +import {displayConfiguration, removeRemoteMount, setProviderState} from '../../../redux/actions/mount_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 { @@ -20,7 +23,8 @@ const mapStateToProps = (state, ownProps) => { const mapDispatchToProps = dispatch => { return { - displayConfiguration: provider => dispatch(displayConfiguration(provider)), + displayConfiguration: (provider, remote) => dispatch(displayConfiguration(provider, remote)), + removeRemoteMount: provider => dispatch(removeRemoteMount(provider)), setProviderState: (provider, state) => dispatch(setProviderState(provider, state)), } }; @@ -51,7 +55,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { rowSpan={6}> props.displayConfiguration(props.provider) : e=>{e.preventDefault();}} + onClick={props.MState.AllowMount ? ()=>props.displayConfiguration(props.provider, props.remote) : e=>{e.preventDefault();}} src={configureImage} style={{padding: 0, border: 0, margin: 0, ...pointer}} width={'16px'}/> @@ -63,16 +67,17 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { let inputControls = null; if (props.Platform === 'win32') { inputColumnSpan = 20; + const index = props.MState.DriveLetters.indexOf(props.PState.MountLocation); inputControls = ; + selected={index >= 0 ? props.PState.MountLocation : ''}/>; } else { - inputColumnSpan = 58; + inputColumnSpan = 64; inputControls = []; let key = 0; inputControls.push(( @@ -103,12 +108,12 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { const buttonDisplay = props.MState.AllowMount ? (props.MState.Mounted ? 'Unmount' : 'Mount') : ; + width={19}/>; const actionsDisplay = ( - ); - if (retryListCount < Object.keys(this.state.RetryItems).length) { - retryList.push(
); + retryList.push(); + if (++retryCount < Object.keys(this.state.RetryItems).length) { + retryList.push(
); } } } retryDisplay = ( - -

Mount Failed

+ +

Mount Failed

{retryList}
) } + let footerItems = []; + if (this.props.remoteSupported) { + footerItems.push(); + } else { + footerItems.push(
); + } + let items = []; for (const provider of Constants.PROVIDER_LIST) { items.push(( this.handleMountLocationChanged(provider, e.target.value)} clicked={this.handleMountUnMount} - key={'mi_' + items.length} + key={'it_' + items.length} provider={provider}/> )); - if (items.length !== this.state.length) { - items.push(
) + items.push(
) + } + + if (this.props.remoteSupported) { + for (const provider of this.props.RemoteMounts) { + items.push(( + this.handleMountLocationChanged(provider, e.target.value)} + clicked={this.handleMountUnMount} + key={'it_' + items.length} + provider={provider} + remote/> + )); + items.push(
) } + items.splice(items.length - 1, 1); + } else { + items.splice(items.length - 1, 1) } return ( -
+
{retryDisplay} - {items} +
+ {items} +
+
+ {footerItems}
); } } @@ -326,6 +396,7 @@ const mapStateToProps = state => { MountsBusy: state.mounts.MountsBusy, Platform: state.common.Platform, ProviderState: state.mounts.ProviderState, + RemoteMounts: state.mounts.RemoteMounts, } }; @@ -334,7 +405,7 @@ const mapDispatchToProps = dispatch => { notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)), resetMountsState: () => dispatch(resetMountsState()), setAllowMount: (provider, allow) => dispatch(setAllowMount(provider, allow)), - setAutoMountProcessed: processed => dispatch(setAutoMountProcessed(processed)), + 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)), diff --git a/src/containers/SelectAppPlatform/SelectAppPlatform.css b/src/containers/SelectAppPlatform/SelectAppPlatform.css index 723c7f6..b1eacb2 100644 --- a/src/containers/SelectAppPlatform/SelectAppPlatform.css +++ b/src/containers/SelectAppPlatform/SelectAppPlatform.css @@ -8,7 +8,7 @@ max-height: 60vh; width: 255px; overflow-y: auto; - margin-bottom: 8px; + margin-bottom: var(--default_spacing); } .SAPActions { diff --git a/src/containers/SelectAppPlatform/SelectAppPlatform.js b/src/containers/SelectAppPlatform/SelectAppPlatform.js index c24e200..5f1a550 100644 --- a/src/containers/SelectAppPlatform/SelectAppPlatform.js +++ b/src/containers/SelectAppPlatform/SelectAppPlatform.js @@ -48,21 +48,25 @@ class SelectAppPlatform extends IPCContainer { this.grabLatestRelease(Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]) }; + handleChanged = e => { + this.setState({ + ...this.state, + Selected: Constants.LINUX_SELECTABLE_PLATFORMS.indexOf(e.target.value), + }); + }; + render() { return ( - +

Select Linux Platform

Repertory was unable to detect your Linux distribution. Please select one of the following and click Test to continue:

- this.setState({ - ...this.state, - Selected: e.target.value - })} + + selected={Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected]}/>
diff --git a/src/helpers.js b/src/helpers.js index 18ba201..697993a 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -8,10 +8,6 @@ const spawn = require('child_process').spawn; const Constants = require('./constants'); const RandomString = require('randomstring'); -const _getDataDirectory = () => { - return _resolvePath(Constants.DATA_LOCATIONS[os.platform()]); -}; - const _executeProcess = (command, args=[]) => { return new Promise((resolve, reject) => { const processOptions = { @@ -61,6 +57,26 @@ const _execProcessGetOutput = (cmd, args) => { }); }; +const _getDataDirectory = () => { + return _resolvePath(Constants.DATA_LOCATIONS[os.platform()]); +}; + +const _getDefaultRepertoryArgs = (provider, remote) => { + const providerLower = provider.toLowerCase(); + const args = []; + if (remote) { + args.push('-rm'); + args.push(provider.substr(6)); + } else if (Constants.PROVIDER_ARG[providerLower] && (Constants.PROVIDER_ARG[providerLower].length > 0)) { + args.push(Constants.PROVIDER_ARG[providerLower]); + } + return args; +}; + +const _getRepertoryExec = version => { + return path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); +}; + const _resolvePath = str => { if (os.platform() === 'win32') { return str.replace(/%([^%]+)%/g, (_, n) => { @@ -71,7 +87,7 @@ const _resolvePath = str => { } }; -const tryParse = (j, def) => { +const _tryParse = (j, def) => { try { return JSON.parse(j); } catch (e) { @@ -87,12 +103,9 @@ module.exports.checkDaemonVersion = (version, provider) => { windowsHide: true, }; - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = []; + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, false); args.push('-cv'); - if (Constants.PROVIDER_ARG[provider.toLowerCase()].length > 0) { - args.push(Constants.PROVIDER_ARG[provider.toLowerCase()]); - } const process = new spawn(command, args, processOptions); @@ -130,41 +143,51 @@ module.exports.createSignatureFiles = (signature, publicKey) => { }; }; -module.exports.detectRepertoryMounts = version => { +module.exports.detectRepertoryMounts = (version, providerList) => { return new Promise((resolve, reject) => { - const processOptions = { - detached: true, - shell: false, - windowsHide: true, - }; - - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = []; - args.push('-status'); - - const process = new spawn(command, args, processOptions); - let result = ''; - - process.on('error', (err) => { - reject(err); - }); - - process.stdout.on('data', (d)=> { - result += d; - }); - - process.on('exit', () => { - let defaultData = {}; - for (const provider of Constants.PROVIDER_LIST) { - defaultData[provider] = { - Active: false, - Location: '', - PID: -1, + let mountState = {}; + const defaultData = {}; + for (const provider of providerList) { + defaultData[provider] = { + Active: false, + Location: '', + PID: -1, + }; + } + const grabStatus = index => { + if (index >= providerList.length) { + resolve(mountState); + } else { + const provider = providerList[index]; + const processOptions = { + detached: true, + shell: false, + windowsHide: true, }; + + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, !Constants.PROVIDER_LIST.includes(provider)); + args.push('-status'); + + const process = new spawn(command, args, processOptions); + let result = ''; + + process.on('error', (err) => { + reject(err); + }); + + process.stdout.on('data', (d) => { + result += d; + }); + + process.on('exit', () => { + mountState[provider] = _tryParse(result, defaultData)[provider]; + grabStatus(++index); + }); + process.unref(); } - resolve(tryParse(result, defaultData)); - }); - process.unref(); + }; + grabStatus(0); }); }; @@ -320,7 +343,7 @@ module.exports.executeScript = script => { }); }; -module.exports.executeMount = (version, provider, location, noConsoleSupported, exitCallback) => { +module.exports.executeMount = (version, provider, remote, location, noConsoleSupported, exitCallback) => { return new Promise((resolve) => { const processOptions = { detached: false, @@ -328,11 +351,8 @@ module.exports.executeMount = (version, provider, location, noConsoleSupported, stdio: 'ignore', }; - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = []; - if (Constants.PROVIDER_ARG[provider.toLowerCase()].length > 0) { - args.push(Constants.PROVIDER_ARG[provider.toLowerCase()]); - } + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, remote); if ((os.platform() === 'linux') || (os.platform() === 'darwin')) { args.push('-o'); @@ -365,7 +385,7 @@ module.exports.executeMount = (version, provider, location, noConsoleSupported, }); }; -module.exports.getConfig = (version, provider) => { +module.exports.getConfig = (version, provider, remote) => { return new Promise((resolve, reject) => { const processOptions = { detached: true, @@ -373,12 +393,9 @@ module.exports.getConfig = (version, provider) => { windowsHide: true, }; - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = []; + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, remote); args.push('-dc'); - if (Constants.PROVIDER_ARG[provider.toLowerCase()].length > 0) { - args.push(Constants.PROVIDER_ARG[provider.toLowerCase()]); - } const process = new spawn(command, args, processOptions); let result = ''; @@ -411,7 +428,7 @@ module.exports.getConfig = (version, provider) => { }); }; -module.exports.getConfigTemplate = (version, provider) => { +module.exports.getConfigTemplate = (version, provider, remote) => { return new Promise((resolve, reject) => { const processOptions = { detached: true, @@ -419,12 +436,9 @@ module.exports.getConfigTemplate = (version, provider) => { windowsHide: true, }; - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = []; + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, remote); args.push('-gt'); - if (Constants.PROVIDER_ARG[provider.toLowerCase()].length > 0) { - args.push(Constants.PROVIDER_ARG[provider.toLowerCase()]); - } const process = new spawn(command, args, processOptions); let result = ''; @@ -598,7 +612,7 @@ module.exports.performWindowsUninstall = names => { parseLine(++index); } }) - .catch(err=> { + .catch(() => { parseLine(++index); }); } else { @@ -635,7 +649,7 @@ module.exports.removeDirectoryRecursively = (p) => { module.exports.resolvePath = _resolvePath; -module.exports.setConfigValue = (name, value, provider, version) => { +module.exports.setConfigValue = (name, value, provider, remote, version) => { return new Promise((resolve, reject) => { const processOptions = { detached: true, @@ -643,14 +657,11 @@ module.exports.setConfigValue = (name, value, provider, version) => { windowsHide: true, }; - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = []; + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, remote); args.push('-set'); args.push(name); args.push(value); - if (Constants.PROVIDER_ARG[provider.toLowerCase()].length > 0) { - args.push(Constants.PROVIDER_ARG[provider.toLowerCase()]); - } const process = new spawn(command, args, processOptions); @@ -666,7 +677,7 @@ module.exports.setConfigValue = (name, value, provider, version) => { }); }; -module.exports.stopMountProcess = (version, provider) => { +module.exports.stopMountProcess = (version, provider, remote) => { return new Promise((resolve, reject) => { const processOptions = { detached: os.platform() === 'darwin', @@ -674,11 +685,9 @@ module.exports.stopMountProcess = (version, provider) => { windowsHide: true, }; - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = ['-unmount']; - if (Constants.PROVIDER_ARG[provider.toLowerCase()].length > 0) { - args.push(Constants.PROVIDER_ARG[provider.toLowerCase()]); - } + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, remote); + args.push('-unmount'); const process = new spawn(command, args, processOptions); const pid = process.pid; @@ -698,18 +707,16 @@ module.exports.stopMountProcess = (version, provider) => { }); }; -module.exports.stopMountProcessSync = (version, provider) => { +module.exports.stopMountProcessSync = (version, provider, remote) => { const processOptions = { detached: true, shell: os.platform() !== 'darwin', windowsHide: true, }; - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); - const args = ['-unmount']; - if (Constants.PROVIDER_ARG[provider.toLowerCase()].length > 0) { - args.push(Constants.PROVIDER_ARG[provider.toLowerCase()]); - } + const command = _getRepertoryExec(version); + const args = _getDefaultRepertoryArgs(provider, remote); + args.push('-unmount'); const process = new spawn(command, args, processOptions); process.unref(); @@ -717,7 +724,7 @@ module.exports.stopMountProcessSync = (version, provider) => { module.exports.testRepertoryBinary = version => { return new Promise((resolve, reject) => { - const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory'); + const command = _getRepertoryExec(version); _executeProcess(command, ['-dc']) .then(code => { if (code === 0) { diff --git a/src/index.css b/src/index.css index df07952..ce1f473 100644 --- a/src/index.css +++ b/src/index.css @@ -1,21 +1,22 @@ :root { --border_radius: 4px; - --control_background: rgba(125, 145, 200, .15); - --control_background_hover: rgba(125, 145, 200, .30); - --control_border: 1px solid rgba(70, 70, 70, 0.9); - --control_box_shadow: 1px 1px 1px black; - --control_transparent_background: rgba(30, 30, 50, 0.3); - --control_dark_transparent_background: rgba(10, 10, 20, 0.8); + --control_background: rgba(105, 105, 150, 0.2); + --control_background_hover: rgba(105, 105, 150, 0.4); + --control_border: 1px solid rgba(80, 80, 90, 0.9); + --control_box_shadow: 2px 2px 2px black; + --control_transparent_background: rgba(10, 10, 16, 0.5); + --control_dark_transparent_background: rgba(10, 10, 16, 0.7); - --text_color: rgba(200, 205, 225, 0.8); - --text_color_hover: rgba(200, 205, 225, 0.9); - --text_color_error: rgba(203, 120, 120, 0.8); - --heading_text_color: rgba(146, 175, 220, 0.7); + --text_color: rgba(200, 200, 240, 0.7); + --text_color_hover: rgba(200, 200, 225, 0.7); + --text_color_error: rgba(203, 120, 120, 0.7); + --heading_text_color: rgba(132, 160, 230, 0.7); --heading_other_text_color: var(--heading_text_color); --text_color_transition: color 0.3s; - --default_font_size: 14px + --default_font_size: 14px; + --default_spacing: 8px; } * { @@ -43,8 +44,8 @@ p { padding: 0; margin: 0; color: var(--text_color); - font-size: medium; - font-weight: bold; + font-size: var(--default_font_size); + font-weight: normal; text-align: center; } @@ -78,7 +79,7 @@ p { } .scrollable-content, ::-webkit-scrollbar { - width: 10px; + width: 8px; } .scrollable-content, ::-webkit-scrollbar * { @@ -86,5 +87,5 @@ p { } .scrollable-content, ::-webkit-scrollbar-thumb { - background: rgba(90, 90, 90, 0.6) !important; + background: var(--control_background_hover) !important; } diff --git a/src/index.js b/src/index.js index ccf8385..22a184f 100644 --- a/src/index.js +++ b/src/index.js @@ -16,19 +16,22 @@ const ipcRenderer = getIPCRenderer(); let store; if (ipcRenderer) { - ipcRenderer.on(Constants.IPC_Get_Platform_Reply, (event, arg) => { - if (arg.Platform === 'linux') { + ipcRenderer.once(Constants.IPC_Get_Platform_Reply, (event, platformInfo) => { + if (platformInfo.Platform === 'linux') { const root = document.documentElement; root.style.setProperty('--default_font_size', '15.3px'); } - store = createAppStore(arg.Platform, arg.AppPlatform, packageJson.version); - ipcRenderer.on(Constants.IPC_Get_State_Reply, (event, arg) => { - if (arg.data) { - store.dispatch(setActiveRelease(arg.data.Release, arg.data.Version)); - - for (const provider of Constants.PROVIDER_LIST) { - let state = arg.data[provider] || this.props.ProviderState[provider]; + ipcRenderer.once(Constants.IPC_Get_State_Reply, (event, result) => { + if (result.data) { + store = createAppStore(platformInfo, packageJson.version, result.data); + store.dispatch(setActiveRelease(result.data.Release, result.data.Version)); + const providerList = [ + ...Constants.PROVIDER_LIST, + ...store.getState().mounts.RemoteMounts, + ]; + for (const provider of providerList) { + let state = result.data[provider] || store.getState().mounts.ProviderState[provider]; if (state.AutoMount === undefined) { state['AutoMount'] = false; } @@ -37,7 +40,10 @@ if (ipcRenderer) { } store.dispatch(setProviderState(provider, state)); } + } else { + store = createAppStore(platformInfo, packageJson.version, {}); } + ReactDOM.render(( diff --git a/src/redux/actions/common_actions.js b/src/redux/actions/common_actions.js index ca9ce7a..f1219b8 100644 --- a/src/redux/actions/common_actions.js +++ b/src/redux/actions/common_actions.js @@ -3,6 +3,26 @@ import {createAction} from 'redux-starter-kit'; import {getIPCRenderer} from '../../utils'; const ipcRenderer = getIPCRenderer(); +let yesNoResolvers = []; + +export const confirmYesNo = title => { + return dispatch => { + return new Promise(resolve => { + dispatch(handleConfirmYesNo(true, title, resolve)); + }); + }; +}; + +export const DISPLAY_CONFIRM_YES_NO = 'common/displayConfirmYesNo'; +const displayConfirmYesNo = (show, title) => { + return { + type: DISPLAY_CONFIRM_YES_NO, + payload: { + show, + title + }, + }; +}; export const displaySelectAppPlatform = display => { return dispatch => { @@ -14,6 +34,25 @@ export const displaySelectAppPlatform = display => { }; }; +export const hideConfirmYesNo = confirmed => { + return dispatch => { + dispatch(handleConfirmYesNo(false, confirmed)); + }; +}; + +const handleConfirmYesNo = (show, titleOrConfirmed, resolve) => { + return dispatch => { + if (show) { + yesNoResolvers.push(resolve); + dispatch(displayConfirmYesNo(show, titleOrConfirmed)); + } else { + yesNoResolvers[0](titleOrConfirmed); + yesNoResolvers.splice(0, 1); + dispatch(displayConfirmYesNo(false)); + } + }; +}; + export const notifyRebootRequired = createAction('common/notifyRebootRequired'); export const rebootSystem = () => { @@ -25,6 +64,33 @@ export const rebootSystem = () => { } }; +export const saveState = () => { + return (dispatch, getState) => { + const state = getState(); + if (state.common.AppReady) { + let currentState = { + Release: state.relver.Release, + RemoteMounts: state.mounts.RemoteMounts, + Version: state.relver.Version, + }; + + const providerList = [ + ...Constants.PROVIDER_LIST, + ...state.mounts.RemoteMounts, + ]; + for (const provider of providerList) { + currentState[provider] = state.mounts.ProviderState[provider]; + } + + if (ipcRenderer) { + ipcRenderer.send(Constants.IPC_Save_State, { + State: currentState + }); + } + } + }; +}; + export const setAllowMount = createAction('common/setAllowMount'); export const setApplicationReady = createAction('common/setApplicationReady'); @@ -60,26 +126,4 @@ export const shutdownApplication = () => { ipcRenderer.send(Constants.IPC_Shutdown); } }; -}; - -export const saveState = () => { - return (dispatch, getState) => { - const state = getState(); - if (state.common.AppReady) { - let currentState = { - Release: state.relver.Release, - Version: state.relver.Version, - }; - - for (const provider of Constants.PROVIDER_LIST) { - currentState[provider] = state.mounts.ProviderState[provider]; - } - - if (ipcRenderer) { - ipcRenderer.send(Constants.IPC_Save_State, { - State: currentState - }); - } - } - }; }; \ No newline at end of file diff --git a/src/redux/actions/mount_actions.js b/src/redux/actions/mount_actions.js index 0539285..e618779 100644 --- a/src/redux/actions/mount_actions.js +++ b/src/redux/actions/mount_actions.js @@ -1,8 +1,85 @@ import * as Constants from '../../constants'; import {createAction} from 'redux-starter-kit'; import {getIPCRenderer} from '../../utils'; +import { + confirmYesNo, + saveState +} from './common_actions'; +import {notifyError} from './error_actions'; -export const displayConfiguration = createAction('mounts/displayConfiguration'); +export const addRemoteMount = (hostNameOrIp, port, token) => { + return (dispatch, getState) => { + const ipcRenderer = getIPCRenderer(); + + const provider = 'Remote' + hostNameOrIp + ':' + port; + dispatch(addRemoteMount2(provider)); + dispatch(setBusy(true)); + + ipcRenderer.once(Constants.IPC_Set_Config_Values_Reply, (_, arg) => { + if (arg.data.Success) { + ipcRenderer.send(Constants.IPC_Detect_Mount, { + Provider: provider, + RemoteMounts: getState().mounts.RemoteMounts, + Version: getState().relver.InstalledVersion, + }); + } else { + dispatch(notifyError('Failed to set \'RemoteToken\': ' + arg.data.Error)); + dispatch(setBusy(false)); + } + }); + + ipcRenderer.send(Constants.IPC_Set_Config_Values, { + Items: [ + {Name: 'RemoteMount.RemoteHostNameOrIp', Value: hostNameOrIp}, + {Name: 'RemoteMount.RemoteToken', Value: token}, + {Name: 'RemoteMount.RemotePort', Value: port}, + {Name: 'RemoteMount.IsRemoteMount', Value: 'true'}, + ], + Provider: provider, + Remote: true, + Version: getState().relver.InstalledVersion, + }); + }; +}; + +export const addRemoteMount2 = createAction('mounts/addRemoteMount2'); + +export const DISPLAY_CONFIGURATION = 'mounts/displayConfiguration'; +export const displayConfiguration = (provider, remote) => { + return { + type: DISPLAY_CONFIGURATION, + payload: { + provider, + remote, + }, + }; +}; + +export const removeRemoteMount = provider => { + return dispatch => { + dispatch(confirmYesNo('Delete [' + provider.substr(6) + ']?')) + .then(confirmed => { + if (confirmed) { + dispatch(removeRemoteMount2(provider)); + } + }); + }; +}; + +const removeRemoteMount2 = provider => { + return dispatch => { + const ipcRenderer = getIPCRenderer(); + ipcRenderer.once(Constants.IPC_Remove_Remote_Mount_Reply, (_, arg) => { + if (arg.data.Success) { + dispatch(removeRemoteMount3(provider)); + dispatch(saveState()); + } + }); + ipcRenderer.send(Constants.IPC_Remove_Remote_Mount, provider.substr(6)); + }; +}; + +export const removeRemoteMount3 = createAction('mounts/removeRemoteMount3'); export const RESET_MOUNTS_STATE = 'mounts/resetMountsState'; export const resetMountsState = () => { @@ -23,7 +100,17 @@ export const setAllowMount = (provider, allow) => { }; }; -export const setAutoMountProcessed = createAction('mounts/setAutoMountProcessed'); +export const SET_AUTO_MOUNT_PROCESSED = 'mounts/setAutoMountProcessed'; +export const setAutoMountProcessed = (provider, processed) => { + return { + type: SET_AUTO_MOUNT_PROCESSED, + payload: { + provider, + processed + } + }; +}; + export const setBusy = createAction('mounts/setBusy'); export const SET_MOUNT_STATE = 'mounts/setMountState'; diff --git a/src/redux/actions/release_version_actions.js b/src/redux/actions/release_version_actions.js index 0fe9ebd..672f8a6 100644 --- a/src/redux/actions/release_version_actions.js +++ b/src/redux/actions/release_version_actions.js @@ -53,13 +53,17 @@ export const loadReleases = () => { return (dispatch, getState) => { const dispatchActions = (locationsLookup, versionLookup)=> { const state = getState().relver; - let latestVersion = versionLookup[Constants.RELEASE_TYPES[state.Release]].length - 1; let release = state.Release; + if (release >= Constants.RELEASE_TYPES.length) { + release = state.ReleaseDefault; + } + + let latestVersion = versionLookup[Constants.RELEASE_TYPES[release]].length - 1; let version = state.Version; if (versionLookup[Constants.RELEASE_TYPES[release]][0] === 'unavailable') { release = state.ReleaseDefault; - latestVersion = version = 0; - } else if ((version === -1) || !versionLookup[Constants.RELEASE_TYPES[state.Release]][version]) { + version = latestVersion = versionLookup[Constants.RELEASE_TYPES[release]].length - 1 + } else if ((version === -1) || !versionLookup[Constants.RELEASE_TYPES[release]][version]) { version = latestVersion; } @@ -135,10 +139,14 @@ export const notifyActiveRelease = (release, version) => { export const setActiveRelease = (release, version) => { return (dispatch, getState) => { dispatch(setAllowMount(false)); - const relVer = getState().relver; + const relver = getState().relver; const common = getState().common; - const versions = relVer.VersionLookup[Constants.RELEASE_TYPES[release]]; - dispatch(setAllowDismissDependencies(versions.length > 1)); + if (release >= Constants.RELEASE_TYPES.length) { + release = relver.ReleaseDefault; + version = -1; + } + const versions = relver.VersionLookup[Constants.RELEASE_TYPES[release]]; + dispatch(setAllowDismissDependencies(versions && (versions.length > 1))); dispatch(setDismissDependencies(false)); dispatch(notifyActiveRelease(release, version)); if (common.AppReady) { diff --git a/src/redux/reducers/common_reducer.js b/src/redux/reducers/common_reducer.js index 1502396..173db4b 100644 --- a/src/redux/reducers/common_reducer.js +++ b/src/redux/reducers/common_reducer.js @@ -1,5 +1,6 @@ import {createReducer} from 'redux-starter-kit'; import { + DISPLAY_CONFIRM_YES_NO, notifyRebootRequired, setAllowMount, setApplicationReady, @@ -7,16 +8,25 @@ import { SET_DISPLAY_SELECT_APPPLATFORM } from '../actions/common_actions'; -export const createCommonReducer = (platform, appPlatform, version) => { +export const createCommonReducer = (platformInfo, version) => { return createReducer({ AllowMount: false, - AppPlatform: appPlatform, + AppPlatform: platformInfo.AppPlatform, AppReady: false, + DisplayConfirmYesNo: false, + ConfirmTitle: null, DisplaySelectAppPlatform: false, - Platform: platform, + 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, + } + }, [SET_DISPLAY_SELECT_APPPLATFORM]: (state, action) => { return { ...state, diff --git a/src/redux/reducers/mount_reducer.js b/src/redux/reducers/mount_reducer.js index 75e25a7..4499e11 100644 --- a/src/redux/reducers/mount_reducer.js +++ b/src/redux/reducers/mount_reducer.js @@ -1,124 +1,194 @@ import * as Constants from '../../constants'; import {createReducer} from 'redux-starter-kit'; import { - displayConfiguration, + addRemoteMount2, + DISPLAY_CONFIGURATION, + removeRemoteMount3, RESET_MOUNTS_STATE, SET_ALLOW_MOUNT, - setAutoMountProcessed, + SET_AUTO_MOUNT_PROCESSED, setBusy, SET_MOUNT_STATE, SET_MOUNTED, SET_PROVIDER_STATE } from '../actions/mount_actions'; -const providerState = Constants.PROVIDER_LIST.map(provider=> { - return { - [provider]: { - AutoMount: false, - AutoRestart: false, - MountLocation: '', +export const createMountReducer = state => { + let providerList = [ + ...Constants.PROVIDER_LIST, + ...(state.RemoteMounts||[]), + ]; + const providerState = providerList.map(provider=> { + return { + [provider]: { + AutoMount: false, + AutoRestart: false, + MountLocation: '', + } } - } -}).reduce((map, obj) => { - return { - ...map, - ...obj - } -}); + }).reduce((map, obj) => { + return { + ...map, + ...obj + } + }); -const mountState = Constants.PROVIDER_LIST.map(provider => { - return { - [provider]: { - AllowMount: false, - DriveLetters: [], - Mounted: false, + const mountState = providerList.map(provider => { + return { + [provider]: { + AllowMount: false, + DriveLetters: [], + Mounted: false, + } } - } -}).reduce((map, obj) => { - return { - ...map, - ...obj - } -}); + }).reduce((map, obj) => { + return { + ...map, + ...obj + } + }); -export const mountReducer = createReducer({ - AutoMountProcessed: false, - DisplayConfiguration: null, - MountsBusy: false, - MountState: mountState, - ProviderState: providerState, -}, { - [displayConfiguration]: (state, action) => { + const autoMountProcessed = providerList.map(provider => { return { - ...state, - DisplayConfiguration: action.payload - }; - }, - [RESET_MOUNTS_STATE]: (state, action) => { - return { - ...state, - MountsBusy: false, - MountState: mountState, + [provider]: false, } - }, - [setAutoMountProcessed]: (state, action) => { + }).reduce((map, obj) => { return { - ...state, - AutoMountProcessed: action.payload - }; - }, - [SET_ALLOW_MOUNT]: (state, action) => { - return { - ...state, - MountState: { - ...state.MountState, - [action.payload.provider]: { - ...state.MountState[action.payload.provider], - AllowMount: action.payload.allow, + ...map, + ...obj + } + }); + + return createReducer({ + AutoMountProcessed: autoMountProcessed, + DisplayConfiguration: null, + DisplayRemoteConfiguration: false, + MountsBusy: false, + MountState: mountState, + ProviderState: providerState, + RemoteMounts: state.RemoteMounts ? state.RemoteMounts : [], + }, { + [addRemoteMount2]: (state, action) => { + let mountState = {...state.MountState}; + mountState[action.payload] = { + AllowMount: false, + DriveLetters: [], + Mounted: false, + }; + + let providerState = {...state.ProviderState}; + providerState[action.payload] = { + AutoMount: false, + AutoRestart: false, + MountLocation: '', + }; + + let autoMountProcessed = {...state.AutoMountProcessed}; + autoMountProcessed[action.payload] = true; + + return { + ...state, + AutoMountProcessed: autoMountProcessed, + MountState: mountState, + ProviderState: providerState, + RemoteMounts: [...state.RemoteMounts, action.payload], + } + }, + [DISPLAY_CONFIGURATION]: (state, action) => { + return { + ...state, + DisplayConfiguration: action.payload.provider, + DisplayRemoteConfiguration: action.payload.remote, + }; + }, + [removeRemoteMount3]: (state, action) => { + let mountState = {...state.MountState}; + delete mountState[action.payload]; + + let providerState = {...state.ProviderState}; + delete providerState[action.payload]; + + let autoMountProcessed = {...state.AutoMountProcessed}; + delete autoMountProcessed[action.payload]; + + const remoteMounts = state.RemoteMounts.filter(i => i !== action.payload); + return { + ...state, + AutoMountProcessed: autoMountProcessed, + MountState: mountState, + ProviderState: providerState, + RemoteMounts: remoteMounts, + }; + }, + [RESET_MOUNTS_STATE]: (state, action) => { + return { + ...state, + MountsBusy: false, + MountState: mountState, + } + }, + [SET_AUTO_MOUNT_PROCESSED]: (state, action) => { + return { + ...state, + AutoMountProcessed: { + ...state.AutoMountProcessed, + [action.payload.provider]: action.payload.processed, } - } - }; - }, - [setBusy]: (state, action) => { - return { - ...state, - MountsBusy: action.payload - }; - }, - [SET_MOUNT_STATE]: (state, action) => { - return { - ...state, - MountState: { - ...state.MountState, - [action.payload.provider]: { - ...state.MountState[action.payload.provider], - ...action.payload.state - }, - } - }; - }, - [SET_MOUNTED]: (state, action) => { - return { - ...state, - MountState: { - ...state.MountState, - [action.payload.provider]: { - ...state.MountState[action.payload.provider], - Mounted: action.payload.mounted, + }; + }, + [SET_ALLOW_MOUNT]: (state, action) => { + return { + ...state, + MountState: { + ...state.MountState, + [action.payload.provider]: { + ...state.MountState[action.payload.provider], + AllowMount: action.payload.allow, + } } - } - }; - }, - [SET_PROVIDER_STATE]: (state, action) => { - return { - ...state, - ProviderState: { - ...state.ProviderState, - [action.payload.provider]: { - ...state.ProviderState[action.payload.provider], - ...action.payload.state - }, - } - }; - } -}); \ No newline at end of file + }; + }, + [setBusy]: (state, action) => { + return { + ...state, + MountsBusy: action.payload + }; + }, + [SET_MOUNT_STATE]: (state, action) => { + return { + ...state, + MountState: { + ...state.MountState, + [action.payload.provider]: { + ...state.MountState[action.payload.provider], + ...action.payload.state + }, + } + }; + }, + [SET_MOUNTED]: (state, action) => { + return { + ...state, + MountState: { + ...state.MountState, + [action.payload.provider]: { + ...state.MountState[action.payload.provider], + Mounted: action.payload.mounted, + } + } + }; + }, + [SET_PROVIDER_STATE]: (state, action) => { + return { + ...state, + ProviderState: { + ...state.ProviderState, + [action.payload.provider]: { + ...state.ProviderState[action.payload.provider], + ...action.payload.state + }, + } + }; + } + }); +}; \ No newline at end of file diff --git a/src/redux/store/createAppStore.js b/src/redux/store/createAppStore.js index acb659c..bbb84de 100644 --- a/src/redux/store/createAppStore.js +++ b/src/redux/store/createAppStore.js @@ -3,16 +3,16 @@ 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 {mountReducer} from '../reducers/mount_reducer'; +import {createMountReducer} from '../reducers/mount_reducer'; import {releaseVersionReducer} from '../reducers/release_version_reducer'; -export default function createAppStore(platform, appPlatform, version) { +export default function createAppStore(platformInfo, version, state) { const reducer = { - common: createCommonReducer(platform, appPlatform, version), + common: createCommonReducer(platformInfo, version), download: downloadReducer, error: errorReducer, install: installReducer, - mounts: mountReducer, + mounts: createMountReducer(state), relver: releaseVersionReducer, }; diff --git a/src/renderer/ipc/ConfigIPC.js b/src/renderer/ipc/ConfigIPC.js index 6f15ba0..76bba25 100644 --- a/src/renderer/ipc/ConfigIPC.js +++ b/src/renderer/ipc/ConfigIPC.js @@ -4,7 +4,7 @@ const helpers = require('../../helpers'); const addListeners = (ipcMain, standardIPCReply) => { ipcMain.on(Constants.IPC_Get_Config, (event, data) => { helpers - .getConfig(data.Version, data.Provider) + .getConfig(data.Version, data.Provider, data.Remote) .then((data) => { if (data.Code === 0) { standardIPCReply(event, Constants.IPC_Get_Config_Reply, { @@ -21,7 +21,7 @@ const addListeners = (ipcMain, standardIPCReply) => { ipcMain.on(Constants.IPC_Get_Config_Template, (event, data) => { helpers - .getConfigTemplate(data.Version, data.Provider) + .getConfigTemplate(data.Version, data.Provider, data.Remote) .then((data) => { standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, { Template: data, @@ -36,7 +36,7 @@ const addListeners = (ipcMain, standardIPCReply) => { const setConfigValue = (i) => { if (i < data.Items.length) { helpers - .setConfigValue(data.Items[i].Name, data.Items[i].Value, data.Provider, data.Version) + .setConfigValue(data.Items[i].Name, data.Items[i].Value, data.Provider, data.Remote, data.Version) .then(() => { setConfigValue(++i); }) diff --git a/src/renderer/ipc/DependencyIPC.js b/src/renderer/ipc/DependencyIPC.js index 6e884f7..ffb9907 100644 --- a/src/renderer/ipc/DependencyIPC.js +++ b/src/renderer/ipc/DependencyIPC.js @@ -72,7 +72,15 @@ const addListeners = (ipcMain, standardIPCReply) => { }; if (data.IsWinFSP) { helpers - .performWindowsUninstall(["WinFsp 2019.1", "WinFsp 2019.2", "WinFsp 2019.3 B1", "WinFsp 2019.3 B2"]) + .performWindowsUninstall([ + "WinFsp 2019.1", + "WinFsp 2019.2", + "WinFsp 2019.3 B1", + "WinFsp 2019.3 B2", + "WinFsp 2019.3 B3", + "WinFsp 2019.3 B4", + "WinFsp 2019.3 B5" + ]) .then(uninstalled => { if (uninstalled) { standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, { @@ -99,4 +107,4 @@ const addListeners = (ipcMain, standardIPCReply) => { module.exports = { addListeners -}; \ No newline at end of file +}; diff --git a/src/renderer/ipc/MountsIPC.js b/src/renderer/ipc/MountsIPC.js index 28add62..9c789cc 100644 --- a/src/renderer/ipc/MountsIPC.js +++ b/src/renderer/ipc/MountsIPC.js @@ -2,6 +2,7 @@ const Constants = require('../../constants'); const fs = require('fs'); const helpers = require('../../helpers'); const os = require('os'); +const path = require('path'); let expectedUnmount = {}; let firstMountCheck = true; @@ -16,10 +17,10 @@ const clearManualMountDetection = provider => { } }; -const monitorMount = (sender, provider, version, pid, location) => { +const monitorMount = (sender, provider, providerList, version, pid, location) => { manualMountDetection[provider] = setInterval(() => { helpers - .detectRepertoryMounts(version) + .detectRepertoryMounts(version, providerList) .then(result => { if (result[provider].PID !== pid) { if (result[provider].PID === -1) { @@ -46,7 +47,7 @@ const monitorMount = (sender, provider, version, pid, location) => { const unmountAllDrives = () => { // Reset mount states - for (const provider of Constants.PROVIDER_LIST) { + for (const provider of Object.keys(manualMountDetection)) { clearManualMountDetection(provider); expectedUnmount[provider] = true; } @@ -54,7 +55,7 @@ const unmountAllDrives = () => { // Unmount all items for (const i in mountedLocations) { const data = mountedData[mountedLocations[i]]; - helpers.stopMountProcessSync(data.Version, data.Provider); + helpers.stopMountProcessSync(data.Version, data.Provider, data.Remote); } mountedLocations = []; @@ -85,9 +86,15 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { event.returnValue = response; }); - ipcMain.on(Constants.IPC_Detect_Mounts, (event, data) => { + ipcMain.on(Constants.IPC_Detect_Mount, (event, data) => { + const provider = data.Provider; + let driveLetters = {}; - for (const provider of Constants.PROVIDER_LIST) { + const providerList = [ + ...Constants.PROVIDER_LIST, + ...data.RemoteMounts, + ]; + for (const provider of providerList) { driveLetters[provider] = []; } @@ -96,7 +103,7 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { const drive = (String.fromCharCode(i) + ':').toUpperCase(); let driveInUse; if (Object.keys(locations).length > 0) { - for (const provider of Constants.PROVIDER_LIST) { + for (const provider of providerList) { driveInUse = locations[provider].startsWith(drive); if (driveInUse) break; @@ -105,7 +112,7 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { if (!driveInUse) { try { if (!fs.existsSync(drive)) { - for (const provider of Constants.PROVIDER_LIST) { + for (const provider of providerList) { driveLetters[provider].push(drive); } } @@ -115,7 +122,7 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { } if (Object.keys(locations).length > 0) { - for (const provider of Constants.PROVIDER_LIST) { + for (const provider of providerList) { if (locations[provider].length > 0) { if (!driveLetters[provider].find((driveLetter) => { return driveLetter === locations[provider]; @@ -130,7 +137,7 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { const setImage = (locations) => { let driveInUse; if (Object.keys(locations).length > 0) { - for (const provider of Constants.PROVIDER_LIST) { + for (const provider of providerList) { driveInUse = locations[provider].length > 0; if (driveInUse) break; @@ -141,11 +148,11 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { }; helpers - .detectRepertoryMounts(data.Version) + .detectRepertoryMounts(data.Version, providerList) .then((results) => { let storageData = {}; let locations = {}; - for (const provider of Constants.PROVIDER_LIST) { + for (const provider of providerList) { storageData[provider] = results[provider] ? results[provider] : { Active: false, Location: '', @@ -156,7 +163,7 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { if (storageData[provider].PID !== -1) { expectedUnmount[provider] = false; if (firstMountCheck) { - monitorMount(event.sender, provider, data.Version, storageData[provider].PID, storageData[provider].Location); + monitorMount(event.sender, provider, providerList, data.Version, storageData[provider].PID, storageData[provider].Location); } } } @@ -169,9 +176,12 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { if (firstMountCheck) { firstMountCheck = false; } - standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, { - DriveLetters: driveLetters, - Locations: locations, + 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 => { @@ -179,8 +189,9 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { grabDriveLetters({}); } setImage({}); - standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, { - DriveLetters: driveLetters, + standardIPCReply(event, Constants.IPC_Detect_Mount_Reply, { + DriveLetters: driveLetters[provider], + Provider: provider, }, error); }); }); @@ -193,8 +204,9 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { } else { mountedLocations.push(data.Location); mountedData[data.Location] = { - Version: data.Version, Provider: data.Provider, + Remote: data.Remote, + Version: data.Version, }; const errorHandler = (pid, error) => { if (mountedLocations.indexOf(data.Location) !== -1) { @@ -206,15 +218,17 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { Expected: expectedUnmount[data.Provider], Location: data.Location, Provider: data.Provider, + Remote: data.Remote, }, error || Error(data.Provider + ' Unmounted')); }; helpers - .executeMount(data.Version, data.Provider, data.Location, data.NoConsoleSupported, (error, pid) => { + .executeMount(data.Version, data.Provider, data.Remote, data.Location, data.NoConsoleSupported, (error, pid) => { errorHandler(pid, error); }) .then(() => { standardIPCReply(event, Constants.IPC_Mount_Drive_Reply, { Provider: data.Provider, + Remote: data.Remote, }); }) .catch(error => { @@ -223,6 +237,18 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { } }); + ipcMain.on(Constants.IPC_Remove_Remote_Mount, (event, data) => { + data = data.replace(':', '_'); + const dataDirectory = path.resolve(path.join(helpers.getDataDirectory(), '..', 'remote', data)); + + try { + helpers.removeDirectoryRecursively(dataDirectory); + standardIPCReply(event, Constants.IPC_Remove_Remote_Mount_Reply, {DataDirectory: dataDirectory}); + } catch (e) { + standardIPCReply(event, Constants.IPC_Remove_Remote_Mount_Reply, {DataDirectory: dataDirectory}, e); + } + }); + ipcMain.on(Constants.IPC_Unmount_All_Drives, (event, data) => { unmountAllDrives(); standardIPCReply(event, Constants.IPC_Unmount_All_Drives_Reply); @@ -233,7 +259,7 @@ const addListeners = (ipcMain, setTrayImage, standardIPCReply) => { expectedUnmount[data.Provider] = true; helpers - .stopMountProcess(data.Version, data.Provider) + .stopMountProcess(data.Version, data.Provider, data.Remote) .then(result => { console.log(result); }) diff --git a/src/utils.js b/src/utils.js index 6d91104..b263338 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,9 +1,16 @@ +import React from 'react'; import * as Constants from './constants'; +import Modal from './components/UI/Modal/Modal'; const ipcRenderer = (!process.versions.hasOwnProperty('electron') && window && window.require) ? window.require('electron').ipcRenderer : null; +export const createModalConditionally = (condition, jsx, critical) => { + const modalProps = {critical: critical}; + return condition ? ({jsx}) : null; +}; + export const extractFileNameFromURL = url => { const parts = url.split('/'); return parts[parts.length - 1];