release v1.3.0

fixes #4
fixes #5
fixes #6
fixes #7
may fix #3

added:
- availability check / error page
- auto switching to next available instance for multiple instances

+ linting / formatting
This commit is contained in:
mrvnklm
2020-08-12 22:56:01 +02:00
parent 634ab476a3
commit 9c93cab40e
12 changed files with 1151 additions and 873 deletions

View File

@@ -3,7 +3,7 @@ name: Build/release
on:
push:
tags:
- '*'
- "*"
jobs:
release:
@@ -30,6 +30,8 @@ jobs:
# (No need to define this secret in the repo settings)
github_token: ${{ secrets.github_token }}
args: "--ia32"
mac_certs: ${{ secrets.mac_certs }}
mac_certs_password: ${{ secrets.mac_certs_password }}

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
node_modules
dist
.idea
.DS_Store

View File

@@ -2,9 +2,9 @@
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
@@ -63,14 +63,14 @@
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
@@ -86,7 +86,7 @@
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
@@ -127,7 +127,7 @@
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
@@ -135,12 +135,12 @@
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
@@ -150,7 +150,7 @@
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
@@ -162,7 +162,7 @@
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
@@ -173,9 +173,9 @@
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
@@ -186,16 +186,16 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Copyright [yyyy][name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,19 +1,26 @@
# Home Assistant - Desktop
Desktop App (Windows / macOS) for [Home Assistant](https://www.home-assistant.io/) built with [Electron](https://www.electronjs.org/)
![Home Assistant - Desktop](https://raw.githubusercontent.com/mrvnklm/homeassistant-desktop/master/media/screenshot.png)
## Installation
Just download the latest version for your platform from the [Releases Section](https://github.com/mrvnklm/homeassistant-desktop/releases) to install Home Assistant
Desktop App (Windows / macOS) for [Home Assistant](https://www.home-assistant.io/) built with [Electron](https://www.electronjs.org)
## Usage
- Click the tray icon to open Home Assistant
- Right-Click to open context menu and change some settings / reset / quit the app
- Updates are installed automatically if a new version is available (restart required)
![Home Assistant - Desktop](https://raw.githubusercontent.com/mrvnklm/homeassistant-desktop/master/media/screenshot.png)
## Installation
Just download the latest version for your platform from the [releases section](https://github.com/mrvnklm/homeassistant-desktop/releases) to install Home Assistant
## Usage / Features
- hover / click the tray icon to open the app
- supports multiple instances of Home Assistant (including automatic switching)
- right-click to open context menu and change some settings / reset / quit the app
- updates are installed automatically if a new version is available (restart required)
## License
Home Assistant Desktop is open-source and [Apache 2](https://choosealicense.com/licenses/apache-2.0/) licensed
## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
I like coffee, so if you feel like buying one for me - go ahead!

422
app.js
View File

@@ -1,196 +1,265 @@
const {app, Menu, Tray, dialog, ipcMain, BrowserWindow, shell, screen} = require('electron');
const {autoUpdater} = require('electron-updater');
const AutoLaunch = require('auto-launch');
const Positioner = require('electron-traywindow-positioner');
const Store = require('electron-store');
const {
app,
dialog,
ipcMain,
shell,
screen,
net,
Menu,
Tray,
BrowserWindow,
} = require("electron");
const { autoUpdater } = require("electron-updater");
const AutoLaunch = require("auto-launch");
const Positioner = require("electron-traywindow-positioner");
const Store = require("electron-store");
app.allowRendererProcessReuse = true;
// prevent multiple instances
if (!app.requestSingleInstanceLock()) {
app.quit()
app.quit();
} else {
app.on('second-instance', () => {
app.on("second-instance", () => {
if (window) showWindow();
})
});
}
// hide dock icon on macOS
if (process.platform === 'darwin') app.dock.hide();
if (process.platform === "darwin") app.dock.hide();
const store = new Store();
const autoLauncher = new AutoLaunch({name: 'Home Assistant Desktop'});
const autoLauncher = new AutoLaunch({ name: "Home Assistant Desktop" });
const indexFile = `file://${__dirname}/web/index.html`;
const errorFile = `file://${__dirname}/web/error.html`;
let autostartEnabled = false;
let forceQuit = false;
let resizeEvent = false;
const useAutoUpdater = () => {
autoUpdater.on('error', message => {
console.error('There was a problem updating the application');
console.error(message)
autoUpdater.on("error", (message) => {
console.error("There was a problem updating the application");
console.error(message);
});
autoUpdater.on('update-downloaded', () => {
autoUpdater.on("update-downloaded", () => {
forceQuit = true;
autoUpdater.quitAndInstall();
});
setInterval(() => {
autoUpdater.checkForUpdates();
}, 1000 * 60 * 30);
}, 1000 * 60 * 60);
autoUpdater.checkForUpdates();
};
const checkAutoStart = () => {
autoLauncher.isEnabled().then((isEnabled) => {
autoLauncher
.isEnabled()
.then((isEnabled) => {
autostartEnabled = isEnabled;
}).catch((err) => {
console.error(err)
})
.catch((err) => {
console.error(err);
});
};
const startAvailabilityCheck = () => {
setInterval(() => {
const request = net.request(`${currentInstance()}/auth/providers`);
request.on("response", (response) => {
showError(response.statusCode !== 200);
});
request.on("error", (error) => {
showError(true);
if (store.get("automaticSwitching")) checkForAvailableInstance();
});
request.end();
}, 3000);
};
const checkForAvailableInstance = () => {
const instances = store.get("allInstances");
if (instances && instances.length > 1) {
instances
.filter((e) => e.url !== currentInstance())
.forEach((e) => {
const request = net.request(`${e}/auth/providers`);
request.on("response", (response) => {
if (response.statusCode === 200) currentInstance(e);
});
request.on("error", (error) => {});
request.end();
});
}
};
const getMenu = () => {
let instancesMenu = [{
label: 'Open in Browser',
let instancesMenu = [
{
label: "Open in Browser",
enabled: currentInstance(),
click: () => {
shell.openExternal(currentInstance())
}
shell.openExternal(currentInstance());
},
},
{
type: 'separator'
}
type: "separator",
},
];
const allInstances = store.get('allInstances');
const allInstances = store.get("allInstances");
if (allInstances) {
allInstances.forEach((e) => {
instancesMenu.push({
label: e,
type: 'checkbox',
type: "checkbox",
checked: currentInstance() === e,
click: () => {
currentInstance(e);
window.loadURL(e);
window.show();
}
},
});
});
instancesMenu.push(
{
type: 'separator'
type: "separator",
},
{
label: 'Add another Instance...', click: () => {
store.delete('currentInstance');
label: "Add another Instance...",
click: () => {
store.delete("currentInstance");
window.loadURL(indexFile);
window.show();
},
},
{
label: "Automatic Switching",
type: "checkbox",
enabled:
store.has("allInstances") && store.get("allInstances").length > 1,
checked: store.get("automaticSwitching"),
click: () => {
store.set("automaticSwitching", store.get("automaticSwitching"));
},
}
}
)
);
} else {
instancesMenu.push({label: 'Not Connected...', enabled: false})
instancesMenu.push({ label: "Not Connected...", enabled: false });
}
return Menu.buildFromTemplate([...instancesMenu,
return Menu.buildFromTemplate([
...instancesMenu,
{
type: 'separator'
type: "separator",
},
{
label: 'Hover to Show',
enabled: !store.get('detachedMode'),
type: 'checkbox',
checked: !store.get('disableHover'),
label: "Hover to Show",
enabled: !store.get("detachedMode"),
type: "checkbox",
checked: !store.get("disableHover"),
click: () => {
store.set('disableHover', !store.get('disableHover'))
}
store.set("disableHover", !store.get("disableHover"));
},
},
{
label: 'Stay on Top',
type: 'checkbox',
label: "Stay on Top",
type: "checkbox",
checked: window.isAlwaysOnTop(),
click: () => {
window.setAlwaysOnTop(!window.isAlwaysOnTop());
if (window.isAlwaysOnTop()) showWindow();
}
},
},
{
label: 'Start at Login',
type: 'checkbox',
label: "Start at Login",
type: "checkbox",
checked: autostartEnabled,
click: () => {
if (autostartEnabled) autoLauncher.disable(); else autoLauncher.enable();
checkAutoStart()
}
}, {
type: 'separator'
if (autostartEnabled) autoLauncher.disable();
else autoLauncher.enable();
checkAutoStart();
},
},
{
label: 'Use detached Window',
type: 'checkbox',
checked: store.get('detachedMode'),
type: "separator",
},
{
label: "Use detached Window",
type: "checkbox",
checked: store.get("detachedMode"),
click: () => {
store.set('detachedMode', !store.get('detachedMode'));
store.set("detachedMode", !store.get("detachedMode"));
window.hide();
createMainWindow(store.get('detachedMode'))
}
createMainWindow(store.get("detachedMode"));
},
},
{
type: 'separator'
type: "separator",
},
{
label: `v${app.getVersion()} (Auto Update)`,
enabled: false
enabled: false,
},
{
label: 'Open on github.com',
label: "Open on github.com",
click: () => {
shell.openExternal('https://github.com/mrvnklm/homeassistant-desktop')
}
shell.openExternal("https://github.com/mrvnklm/homeassistant-desktop");
},
},
{
type: 'separator'
type: "separator",
},
{
label: 'Reload Window',
label: "Reload Window",
click: () => {
window.reload();
}
},
},
{
label: 'Reset Settings...',
label: "Reset Application...",
click: () => {
dialog.showMessageBox({
message: 'Are you sure you want to reset Home Assistant Desktop?',
buttons: ['Cancel', 'OK, Reset!']
}).then((res) => {
if (res.response === 1) {
dialog
.showMessageBox({
message: "Are you sure you want to reset Home Assistant Desktop?",
buttons: ["Reset Everything!", "Reset Windows", "Cancel"],
})
.then((res) => {
if (res.response === 0) {
store.clear();
window.webContents.session.clearCache();
window.webContents.session.clearStorageData();
app.relaunch();
app.exit();
}
})
if (res.response === 1) {
store.delete("windowSizeDetached");
store.delete("windowSize");
store.delete("windowPosition");
app.relaunch();
app.exit();
}
});
},
},
{
type: 'separator'
type: "separator",
},
{
label: 'Quit',
accelerator: 'Cmd+Q',
label: "Quit",
click: () => {
forceQuit = true;
app.quit();
}
}
])
},
},
]);
};
const createMainWindow = (show = false) => {
@@ -202,147 +271,216 @@ const createMainWindow = (show = false) => {
autoHideMenuBar: true,
frame: false,
webPreferences: {
nodeIntegration: true
}
nodeIntegration: true,
},
});
// window.webContents.openDevTools();
window.loadURL(indexFile);
window.webContents.on('did-finish-load', function () {
window.webContents.insertCSS('::-webkit-scrollbar { display: none; } body { -webkit-user-select: none; }');
if (store.get('detachedMode')) {
window.webContents.insertCSS('body { -webkit-app-region: drag; }');
// open extenal links in default browser
window.webContents.on("new-window", function (e, url) {
e.preventDefault();
require("electron").shell.openExternal(url);
});
// hide scrollbar
window.webContents.on("did-finish-load", function () {
window.webContents.insertCSS(
"::-webkit-scrollbar { display: none; } body { -webkit-user-select: none; }"
);
if (store.get("detachedMode")) {
window.webContents.insertCSS("body { -webkit-app-region: drag; }");
}
});
if (store.get('detachedMode')) {
if (store.has('windowPosition')) window.setSize(...store.get('windowSizeDetached')); else store.set('windowPosition', window.getPosition());
if (store.has('windowSizeDetached')) window.setPosition(...store.get('windowPosition')); else store.set('windowSizeDetached', window.getSize())
if (store.get("detachedMode")) {
if (store.has("windowPosition"))
window.setSize(...store.get("windowSizeDetached"));
else store.set("windowPosition", window.getPosition());
if (store.has("windowSizeDetached"))
window.setPosition(...store.get("windowPosition"));
else store.set("windowSizeDetached", window.getSize());
} else {
if (store.has('windowSize')) window.setSize(...store.get('windowSize')); else store.set('windowSize', window.getSize())
if (store.has("windowSize")) window.setSize(...store.get("windowSize"));
else store.set("windowSize", window.getSize());
}
window.on('resize', () => {
if (store.get('detachedMode')) {
store.set('windowSizeDetached', window.getSize());
window.on("resize", (e) => {
if (!store.get("disableHover") || resizeEvent) {
store.set("disableHover", true);
resizeEvent = e;
setTimeout(() => {
if (resizeEvent === e) {
store.set("disableHover", false);
resizeEvent = false;
}
}, 600);
}
if (store.get("detachedMode")) {
store.set("windowSizeDetached", window.getSize());
} else {
Positioner.position(window, tray.getBounds());
store.set('windowSize', window.getSize());
}
});
window.on('move', () => {
if (store.get('detachedMode')) {
store.set('windowPosition', window.getPosition())
store.set("windowSize", window.getSize());
}
});
window.on('close', (e) => {
window.on("move", () => {
if (store.get("detachedMode")) {
store.set("windowPosition", window.getPosition());
}
});
window.on("close", (e) => {
if (!forceQuit) {
window.hide();
e.preventDefault()
e.preventDefault();
}
});
window.on('blur', () => {
if (!store.get('detachedMode') && !window.isAlwaysOnTop()) window.hide();
window.on("blur", () => {
if (!store.get("detachedMode") && !window.isAlwaysOnTop()) window.hide();
});
if (show) showWindow();
};
const showWindow = () => {
if (!store.get('detachedMode')) Positioner.position(window, tray.getBounds());
if (!store.get("detachedMode")) Positioner.position(window, tray.getBounds());
if (!window.isVisible()) {
window.setVisibleOnAllWorkspaces(true); // put the window on all screens
window.show();
window.focus();
window.setVisibleOnAllWorkspaces(false); // disable all screen behavior
}
};
const createTray = () => {
tray = new Tray(process.platform === 'win32' ? `${__dirname}/assets/IconWin.png` : `${__dirname}/assets/IconTemplate.png`);
tray = new Tray(
process.platform === "win32"
? `${__dirname}/assets/IconWin.png`
: `${__dirname}/assets/IconTemplate.png`
);
tray.on('click', () => {
if (window.isVisible()) window.hide(); else showWindow();
tray.on("click", () => {
if (window.isVisible()) window.hide();
else showWindow();
});
tray.on('right-click', () => {
if (!store.get('detachedMode')) window.hide();
tray.popUpContextMenu(getMenu())
tray.on("right-click", () => {
if (!store.get("detachedMode")) window.hide();
tray.popUpContextMenu(getMenu());
});
let timer = undefined;
tray.on('mouse-move', (e) => {
if (store.get('detachedMode') || window.isAlwaysOnTop() || store.get('disableHover')) {
tray.on("mouse-move", (e) => {
if (
store.get("detachedMode") ||
window.isAlwaysOnTop() ||
store.get("disableHover")
) {
return;
}
if (!window.isVisible()) {
showWindow();
}
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
let mousePos = screen.getCursorScreenPoint();
let trayBounds = tray.getBounds();
if (!(mousePos.x >= trayBounds.x && mousePos.x <= trayBounds.x + trayBounds.width) || !(mousePos.y >= trayBounds.y && mousePos.y <= trayBounds.y + trayBounds.height)) {
setWindowFocusTimer()
if (
!(
mousePos.x >= trayBounds.x &&
mousePos.x <= trayBounds.x + trayBounds.width
) ||
!(
mousePos.y >= trayBounds.y &&
mousePos.y <= trayBounds.y + trayBounds.height
)
) {
setWindowFocusTimer();
}
}, 100);
}
)
}
;
});
};
const setWindowFocusTimer = () => {
let timer = setTimeout(() => {
let mousePos = screen.getCursorScreenPoint();
let windowPosition = window.getPosition();
let windowSize = window.getSize();
if (!(mousePos.x >= windowPosition[0] && mousePos.x <= windowPosition[0] + windowSize[0]) || !(mousePos.y >= windowPosition[1] && mousePos.y <= windowPosition[1] + windowSize[1])) {
if (
!resizeEvent &&
(!(
mousePos.x >= windowPosition[0] &&
mousePos.x <= windowPosition[0] + windowSize[0]
) ||
!(
mousePos.y >= windowPosition[1] &&
mousePos.y <= windowPosition[1] + windowSize[1]
))
) {
window.hide();
} else {
setWindowFocusTimer()
setWindowFocusTimer();
}
}, 110)
}, 110);
};
app.on('ready', () => {
// temporary migration of instances to avoid breaking active instance
if (store.has('instance')) {
store.set('allInstances', [store.get('instance').url]);
store.set('currentInstance', 0);
store.delete('instance');
}
app.on("ready", () => {
checkAutoStart();
useAutoUpdater();
createTray();
createMainWindow(!store.has('currentInstance'));
createMainWindow(!store.has("currentInstance"));
startAvailabilityCheck();
// disable hover for first start
if (!store.has("currentInstance")) {
store.set("disableHover", true);
}
});
const currentInstance = (url = null) => {
if (url) {
store.set('currentInstance', store.get('allInstances').indexOf(url));
store.set("currentInstance", store.get("allInstances").indexOf(url));
}
if (store.has('currentInstance')) {
return store.get('allInstances')[store.get('currentInstance')];
if (store.has("currentInstance")) {
return store.get("allInstances")[store.get("currentInstance")];
}
return false;
};
const addInstance = (url) => {
if (!store.has('allInstances')) store.set('allInstances', []);
let instances = store.get('allInstances');
if (instances.find(e => e === url)) {
if (!store.has("allInstances")) store.set("allInstances", []);
let instances = store.get("allInstances");
if (instances.find((e) => e === url)) {
currentInstance(url);
return;
}
// active hover by default after adding first instance
if (!instances.length) store.set("disableHover", false);
instances.push(url);
store.set('allInstances', instances);
currentInstance(url)
store.set("allInstances", instances);
currentInstance(url);
};
ipcMain.on('ha-instance', (event, args) => {
if (args) addInstance(args.url);
console.log(currentInstance());
if (currentInstance()) event.reply('ha-instance', currentInstance())
const showError = (isError) => {
if (!isError && window.webContents.getURL().includes("error.html"))
window.loadURL(indexFile);
if (
isError &&
currentInstance() &&
!window.webContents.getURL().includes("error.html")
)
window.loadURL(errorFile);
};
ipcMain.on("ha-instance", (event, url) => {
if (url) addInstance(url);
if (currentInstance()) event.reply("ha-instance", currentInstance());
});

326
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "homeassistant-desktop",
"version": "1.0.0",
"version": "1.2.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -93,23 +93,23 @@
"dev": true
},
"@types/fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==",
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.1.tgz",
"integrity": "sha512-B42Sxuaz09MhC3DDeW5kubRcQ5by4iuVQ0cRRWM2lggLzAa/KVom0Aft/208NgMvNQQZ86s5rVcqDdn/SH0/mg==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz",
"integrity": "sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA=="
"version": "14.0.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz",
"integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g=="
},
"@types/semver": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.2.0.tgz",
"integrity": "sha512-TbB0A8ACUWZt3Y6bQPstW9QNbhNeebdgLX4T/ZfkrswAfUzRiXrgd9seol+X379Wa589Pu4UEx9Uok0D4RjRCQ==",
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.1.tgz",
"integrity": "sha512-ooD/FJ8EuwlDKOI6D9HWxgIgJjMg2cuziXm/42npDC8y4NjxplBUn9loewZiBNCt44450lHAU0OSb51/UqXeag==",
"requires": {
"@types/node": "*"
}
@@ -130,9 +130,9 @@
"dev": true
},
"ajv": {
"version": "6.12.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
"integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
"version": "6.12.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
"integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -141,9 +141,9 @@
}
},
"ajv-keywords": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
"integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==",
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
},
"ansi-align": {
@@ -185,32 +185,32 @@
}
},
"app-builder-bin": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.8.tgz",
"integrity": "sha512-ni3q7QTfQNWHNWuyn5x3FZu6GnQZv+TFnfgk5++svqleKEhHGqS1mIaKsh7x5pBX6NFXU3/+ktk98wA/AW4EXw==",
"version": "3.5.9",
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.9.tgz",
"integrity": "sha512-NSjtqZ3x2kYiDp3Qezsgukx/AUzKPr3Xgf9by4cYt05ILWGAptepeeu0Uv+7MO+41o6ujhLixTou8979JGg2Kg==",
"dev": true
},
"app-builder-lib": {
"version": "22.6.0",
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.6.0.tgz",
"integrity": "sha512-ky2aLYy92U+Gh6dKq/e8/bNmCotp6/GMhnX8tDZPv9detLg9WuBnWWi1ktBPlpbl1DREusy+TIh+9rgvfduQoA==",
"version": "22.8.0",
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.8.0.tgz",
"integrity": "sha512-RGaIRjCUrqkmh6QOGsyekQPEOaVynHfmeh8JZuyUymFYUOFdzBbPamkA2nhBVBTkkgfjRHsxK7LhedFKPzvWEQ==",
"dev": true,
"requires": {
"7zip-bin": "~5.0.3",
"@develar/schema-utils": "~2.6.5",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.9",
"builder-util": "22.6.0",
"builder-util-runtime": "8.7.0",
"builder-util": "22.8.0",
"builder-util-runtime": "8.7.2",
"chromium-pickle-js": "^0.2.0",
"debug": "^4.1.1",
"ejs": "^3.1.2",
"electron-publish": "22.6.0",
"fs-extra": "^9.0.0",
"hosted-git-info": "^3.0.4",
"ejs": "^3.1.3",
"electron-publish": "22.8.0",
"fs-extra": "^9.0.1",
"hosted-git-info": "^3.0.5",
"is-ci": "^2.0.0",
"isbinaryfile": "^4.0.6",
"js-yaml": "^3.13.1",
"js-yaml": "^3.14.0",
"lazy-val": "^1.0.4",
"minimatch": "^3.0.4",
"normalize-package-data": "^2.5.0",
@@ -355,31 +355,31 @@
"dev": true
},
"builder-util": {
"version": "22.6.0",
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.6.0.tgz",
"integrity": "sha512-jgdES2ExJYkuXC3DEaGAjFctKNA81C4QDy8zdoc+rqdSqheTizuDNtZg02uMFklmUES4V4fggmqds+Y7wraqng==",
"version": "22.8.0",
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.8.0.tgz",
"integrity": "sha512-H80P1JzVy3TGpi63x81epQDK24XalL034+jAZlrPb5IhLtYmnNNdxCCAVJvg3VjSISd73Y71O+uhqCxWpqbPHw==",
"dev": true,
"requires": {
"7zip-bin": "~5.0.3",
"@types/debug": "^4.1.5",
"@types/fs-extra": "^8.1.0",
"app-builder-bin": "3.5.8",
"@types/fs-extra": "^9.0.1",
"app-builder-bin": "3.5.9",
"bluebird-lst": "^1.0.9",
"builder-util-runtime": "8.7.0",
"chalk": "^4.0.0",
"builder-util-runtime": "8.7.2",
"chalk": "^4.1.0",
"debug": "^4.1.1",
"fs-extra": "^9.0.0",
"fs-extra": "^9.0.1",
"is-ci": "^2.0.0",
"js-yaml": "^3.13.1",
"js-yaml": "^3.14.0",
"source-map-support": "^0.5.19",
"stat-mode": "^1.0.0",
"temp-file": "^3.3.7"
}
},
"builder-util-runtime": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz",
"integrity": "sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==",
"version": "8.7.2",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz",
"integrity": "sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA==",
"requires": {
"debug": "^4.1.1",
"sax": "^1.2.4"
@@ -401,9 +401,9 @@
},
"dependencies": {
"get-stream": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
"integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"requires": {
"pump": "^3.0.0"
@@ -424,9 +424,9 @@
"dev": true
},
"chalk": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
"integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
@@ -643,16 +643,16 @@
"optional": true
},
"dmg-builder": {
"version": "22.6.0",
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.6.0.tgz",
"integrity": "sha512-rJxuGhHIpcuDGBtWZMM8aLxkbZNgYO2MO5dUerDIBXebhX1K8DA23iz/uZ8ahcRNgWEv57b8GDqJbXKEfr5T0A==",
"version": "22.8.0",
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.8.0.tgz",
"integrity": "sha512-orePWjcrl97SYLA8F/6UUtbXJSoZCYu5KOP1lVqD4LOomr8bjGDyEVYZmZYcg5WqKmXucdmO6OpqgzH/aRMMuA==",
"dev": true,
"requires": {
"app-builder-lib": "22.6.0",
"builder-util": "22.6.0",
"fs-extra": "^9.0.0",
"iconv-lite": "^0.5.1",
"js-yaml": "^3.13.1",
"app-builder-lib": "22.8.0",
"builder-util": "22.8.0",
"fs-extra": "^9.0.1",
"iconv-lite": "^0.6.2",
"js-yaml": "^3.14.0",
"sanitize-filename": "^1.6.3"
}
},
@@ -683,18 +683,18 @@
"dev": true
},
"ejs": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.2.tgz",
"integrity": "sha512-zFuywxrAWtX5Mk2KAuoJNkXXbfezpNA0v7i+YC971QORguPekpjpAgeOv99YWSdKXwj7JxI2QAWDeDkE8fWtXw==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz",
"integrity": "sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg==",
"dev": true,
"requires": {
"jake": "^10.6.1"
}
},
"electron": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-8.3.0.tgz",
"integrity": "sha512-XRjiIJICZCgUr2vKSUI2PTkfP0gPFqCtqJUaTJSfCTuE3nTrxBKOUNeRMuCzEqspKkpFQU3SB3MdbMSHmZARlQ==",
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-8.5.0.tgz",
"integrity": "sha512-ERqSTRlaQ4PqME5a1z9DWQbwQy2LbgSN1Jnau1MJCRRvHgq1FJlqbbb/ij/RGWuQuaxy4Djb2KnTs5rsemR5mQ==",
"dev": true,
"requires": {
"@electron/get": "^1.0.1",
@@ -703,27 +703,27 @@
},
"dependencies": {
"@types/node": {
"version": "12.12.39",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.39.tgz",
"integrity": "sha512-pADGfwnDkr6zagDwEiCVE4yQrv7XDkoeVa4OfA9Ju/zRTk6YNDLGtQbkdL4/56mCQQCs4AhNrBIag6jrp7ZuOg==",
"version": "12.12.54",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz",
"integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==",
"dev": true
}
}
},
"electron-builder": {
"version": "22.6.0",
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.6.0.tgz",
"integrity": "sha512-aLHlB6DTfjJ3MI4AUIFeWnwIozNgNlbOk2c2sTHxB10cAKp0dBVSPZ7xF5NK0uwDhElvRzJQubnHtJD6zKg42Q==",
"version": "22.8.0",
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.8.0.tgz",
"integrity": "sha512-dUv4F3srJouqxhWivtKqSoQP4Df6vYgjooGdzms+iYMTFi9f0b4LlEbr7kgsPvte8zAglee7VOGOODkCRJDkUQ==",
"dev": true,
"requires": {
"@types/yargs": "^15.0.4",
"app-builder-lib": "22.6.0",
"@types/yargs": "^15.0.5",
"app-builder-lib": "22.8.0",
"bluebird-lst": "^1.0.9",
"builder-util": "22.6.0",
"builder-util-runtime": "8.7.0",
"chalk": "^4.0.0",
"dmg-builder": "22.6.0",
"fs-extra": "^9.0.0",
"builder-util": "22.8.0",
"builder-util-runtime": "8.7.2",
"chalk": "^4.1.0",
"dmg-builder": "22.8.0",
"fs-extra": "^9.0.1",
"is-ci": "^2.0.0",
"lazy-val": "^1.0.4",
"read-config-file": "6.0.0",
@@ -733,25 +733,25 @@
}
},
"electron-publish": {
"version": "22.6.0",
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.6.0.tgz",
"integrity": "sha512-+v05SBf9qR7Os5au+fifloNHy5QxHQkUGudBj68YaTb43Pn37UkwRxSc49Lf13s4wW32ohM45g8BOVInPJEdnA==",
"version": "22.8.0",
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.8.0.tgz",
"integrity": "sha512-uM0Zdi9hUqqGOrPj478v7toTvV1Kgto1w11rIiI168batiXAJvNLD8VZRfehOrZT0ibUyZlw8FtxoGCrjyHUOw==",
"dev": true,
"requires": {
"@types/fs-extra": "^8.1.0",
"@types/fs-extra": "^9.0.1",
"bluebird-lst": "^1.0.9",
"builder-util": "22.6.0",
"builder-util-runtime": "8.7.0",
"chalk": "^4.0.0",
"fs-extra": "^9.0.0",
"builder-util": "22.8.0",
"builder-util-runtime": "8.7.2",
"chalk": "^4.1.0",
"fs-extra": "^9.0.1",
"lazy-val": "^1.0.4",
"mime": "^2.4.4"
"mime": "^2.4.6"
}
},
"electron-store": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-5.1.1.tgz",
"integrity": "sha512-FLidOVE8JVCdJXHd7xY/JojKJ2r2WNmWt0O/LlX2LuSVV7dkG2RSy2/Gm2LFw8OKDfrNBd9c/s4X1ikMrJEUKg==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-5.2.0.tgz",
"integrity": "sha512-iU3WDqEDAYNYR9XV7p0tJajq/zs9z7Nrn0sAoR5nDyn8h/9dr9kusKbTxD8NtVEBD1TB1pkGMqcbIt/y6knDwQ==",
"requires": {
"conf": "^6.2.1",
"type-fest": "^0.7.1"
@@ -763,17 +763,17 @@
"integrity": "sha512-/i1jh1L8qyUJAZ1KVT67SEK/OZ+3F2Qfe8mCfuXHSVC5tAOuw3U971LuxMvAsJJS/yNW0oSQ9pCbVzqGlNCeJQ=="
},
"electron-updater": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.3.1.tgz",
"integrity": "sha512-UDC5AHCgeiHJYDYWZG/rsl1vdAFKqI/Lm7whN57LKAk8EfhTewhcEHzheRcncLgikMcQL8gFo1KeX51tf5a5Wg==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.3.4.tgz",
"integrity": "sha512-ekpgxDrYl+Wi24ktO4qfj2CtCABxrmK1C/oekp0tai6q4VR4ZdPkit4CX8+GenvKMme7uMmfPFnLp/vwhP/ThQ==",
"requires": {
"@types/semver": "^7.1.0",
"builder-util-runtime": "8.7.0",
"fs-extra": "^9.0.0",
"js-yaml": "^3.13.1",
"@types/semver": "^7.3.1",
"builder-util-runtime": "8.7.2",
"fs-extra": "^9.0.1",
"js-yaml": "^3.14.0",
"lazy-val": "^1.0.4",
"lodash.isequal": "^4.5.0",
"semver": "^7.1.3"
"semver": "^7.3.2"
},
"dependencies": {
"semver": {
@@ -824,9 +824,9 @@
"dev": true
},
"escape-string-regexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"optional": true
},
@@ -865,9 +865,9 @@
}
},
"fast-deep-equal": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
@@ -901,9 +901,9 @@
}
},
"fs-extra": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
"integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
@@ -927,19 +927,19 @@
}
},
"global-agent": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.8.tgz",
"integrity": "sha512-VpBe/rhY6Rw2VDOTszAMNambg+4Qv8j0yiTNDYEXXXxkUNGWLHp8A3ztK4YDBbFNcWF4rgsec6/5gPyryya/+A==",
"version": "2.1.12",
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz",
"integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==",
"dev": true,
"optional": true,
"requires": {
"boolean": "^3.0.0",
"core-js": "^3.6.4",
"boolean": "^3.0.1",
"core-js": "^3.6.5",
"es6-error": "^4.1.1",
"matcher": "^2.1.0",
"roarr": "^2.15.2",
"semver": "^7.1.2",
"serialize-error": "^5.0.0"
"matcher": "^3.0.0",
"roarr": "^2.15.3",
"semver": "^7.3.2",
"serialize-error": "^7.0.1"
},
"dependencies": {
"semver": {
@@ -1020,12 +1020,12 @@
"dev": true
},
"hosted-git-info": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.4.tgz",
"integrity": "sha512-4oT62d2jwSDBbLLFLZE+1vPuQ1h8p9wjrJ8Mqx5TjsyWmBMV5B13eJqn8pvluqubLf3cJPTfiYCIwNwDNmzScQ==",
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.5.tgz",
"integrity": "sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ==",
"dev": true,
"requires": {
"lru-cache": "^5.1.1"
"lru-cache": "^6.0.0"
}
},
"http-cache-semantics": {
@@ -1035,12 +1035,12 @@
"dev": true
},
"iconv-lite": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.1.tgz",
"integrity": "sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q==",
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
"import-lazy": {
@@ -1132,9 +1132,9 @@
"dev": true
},
"jake": {
"version": "10.6.1",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.6.1.tgz",
"integrity": "sha512-pHUK3+V0BjOb1XSi95rbBksrMdIqLVC9bJqDnshVyleYsET3H0XAq+3VB2E3notcYvv4wRdRHn13p7vobG+wfQ==",
"version": "10.8.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
"dev": true,
"requires": {
"async": "0.9.x",
@@ -1202,9 +1202,9 @@
}
},
"js-yaml": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
"integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -1284,9 +1284,9 @@
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true,
"optional": true
},
@@ -1302,12 +1302,12 @@
"dev": true
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^3.0.2"
"yallist": "^4.0.0"
}
},
"make-dir": {
@@ -1319,19 +1319,19 @@
}
},
"matcher": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz",
"integrity": "sha512-o+nZr+vtJtgPNklyeUKkkH42OsK8WAfdgaJE2FNxcjLPg+5QbeEoT6vRj8Xq/iv18JlQ9cmKsEu0b94ixWf1YQ==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
"integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
"dev": true,
"optional": true,
"requires": {
"escape-string-regexp": "^2.0.0"
"escape-string-regexp": "^4.0.0"
}
},
"mime": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz",
"integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==",
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
"integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
"dev": true
},
"mimic-fn": {
@@ -1432,9 +1432,9 @@
}
},
"onetime": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
"integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"requires": {
"mimic-fn": "^2.1.0"
}
@@ -1605,9 +1605,9 @@
}
},
"registry-auth-token": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz",
"integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz",
"integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==",
"dev": true,
"requires": {
"rc": "^1.2.8"
@@ -1724,19 +1724,19 @@
}
},
"serialize-error": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-5.0.0.tgz",
"integrity": "sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
"dev": true,
"optional": true,
"requires": {
"type-fest": "^0.8.0"
"type-fest": "^0.13.1"
},
"dependencies": {
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
"dev": true,
"optional": true
}
@@ -1770,9 +1770,9 @@
}
},
"spdx-correct": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
"integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
"dev": true,
"requires": {
"spdx-expression-parse": "^3.0.0",
@@ -2148,15 +2148,15 @@
"dev": true
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"yargs": {
"version": "15.3.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
"integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"dev": true,
"requires": {
"cliui": "^6.0.0",
@@ -2169,7 +2169,7 @@
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.1"
"yargs-parser": "^18.1.2"
},
"dependencies": {
"find-up": {

View File

@@ -4,26 +4,26 @@
"type": "git",
"url": "https://github.com/mrvnklm/homeassistant-desktop"
},
"version": "1.2.1",
"version": "1.3.0",
"description": "Desktop App (Windows / macOS) for Home Assistant built with Electron",
"main": "app.js",
"scripts": {
"start": "electron .",
"build-local": "electron-builder build --mac --win --publish never",
"deploy": "electron-builder build --mac --win --publish always",
"build-local": "electron-builder build --mac --win --ia32 --publish never",
"deploy": "electron-builder build --mac --win --ia32 --publish always",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Marvin Kelm (https://github.com/mrvnklm)",
"license": "Apache-2.0",
"dependencies": {
"auto-launch": "^5.0.5",
"electron-store": "^5.1.1",
"electron-store": "^5.2.0",
"electron-traywindow-positioner": "^1.1.0",
"electron-updater": "^4.3.1"
"electron-updater": "^4.3.4"
},
"devDependencies": {
"electron": "^8.2.5",
"electron-builder": "^22.6.0"
"electron": "^8.5.0",
"electron-builder": "^22.8.0"
},
"build": {
"appId": "com.electron.homeassistant-desktop",

View File

@@ -2,64 +2,65 @@
* Extracted from: SweetAlert
* Modified by: Istiak Tridip
*/
.success-checkmark {
.success-checkmark {
width: 80px;
height: 80px;
margin: 0 auto;
}
.success-checkmark .check-icon {
}
.success-checkmark .check-icon {
width: 80px;
height: 80px;
position: relative;
border-radius: 50%;
box-sizing: content-box;
border: 4px solid #4CAF50;
}
.success-checkmark .check-icon::before {
border: 4px solid #4caf50;
}
.success-checkmark .check-icon::before {
top: 3px;
left: -2px;
width: 30px;
transform-origin: 100% 50%;
border-radius: 100px 0 0 100px;
}
.success-checkmark .check-icon::after {
}
.success-checkmark .check-icon::after {
top: 0;
left: 30px;
width: 60px;
transform-origin: 0 50%;
border-radius: 0 100px 100px 0;
animation: rotate-circle 4.25s ease-in;
}
.success-checkmark .check-icon::before, .success-checkmark .check-icon::after {
}
.success-checkmark .check-icon::before,
.success-checkmark .check-icon::after {
content: "";
height: 100px;
position: absolute;
background: #FFFFFF;
background: #ffffff;
transform: rotate(-45deg);
}
.success-checkmark .check-icon .icon-line {
}
.success-checkmark .check-icon .icon-line {
height: 5px;
background-color: #4CAF50;
background-color: #4caf50;
display: block;
border-radius: 2px;
position: absolute;
z-index: 10;
}
.success-checkmark .check-icon .icon-line.line-tip {
}
.success-checkmark .check-icon .icon-line.line-tip {
top: 46px;
left: 14px;
width: 25px;
transform: rotate(45deg);
animation: icon-line-tip 0.75s;
}
.success-checkmark .check-icon .icon-line.line-long {
}
.success-checkmark .check-icon .icon-line.line-long {
top: 38px;
right: 8px;
width: 47px;
transform: rotate(-45deg);
animation: icon-line-long 0.75s;
}
.success-checkmark .check-icon .icon-circle {
}
.success-checkmark .check-icon .icon-circle {
top: -4px;
left: -4px;
z-index: 10;
@@ -69,8 +70,8 @@
position: absolute;
box-sizing: content-box;
border: 4px solid rgba(76, 175, 80, 0.5);
}
.success-checkmark .check-icon .icon-fix {
}
.success-checkmark .check-icon .icon-fix {
top: 8px;
width: 5px;
left: 26px;
@@ -78,10 +79,10 @@
height: 85px;
position: absolute;
transform: rotate(-45deg);
background-color: #FFFFFF;
}
background-color: #ffffff;
}
@keyframes rotate-circle {
@keyframes rotate-circle {
0% {
transform: rotate(-45deg);
}
@@ -94,8 +95,8 @@
100% {
transform: rotate(-405deg);
}
}
@keyframes icon-line-tip {
}
@keyframes icon-line-tip {
0% {
width: 0;
left: 1px;
@@ -121,8 +122,8 @@
left: 14px;
top: 45px;
}
}
@keyframes icon-line-long {
}
@keyframes icon-line-long {
0% {
width: 0;
right: 46px;
@@ -143,4 +144,4 @@
right: 8px;
top: 38px;
}
}
}

42
web/assets/error.css Normal file
View File

@@ -0,0 +1,42 @@
svg {
width: 100px;
display: block;
margin: 40px auto 0;
}
.path {
stroke-dasharray: 1000;
stroke-dashoffset: 0;
}
.path.circle {
-webkit-animation: dash 0.9s ease-in-out;
animation: dash 0.9s ease-in-out;
}
.path.line {
stroke-dashoffset: 1000;
-webkit-animation: dash 0.9s 0.35s ease-in-out forwards;
animation: dash 0.9s 0.35s ease-in-out forwards;
}
p {
text-align: center;
margin: 20px 0 60px;
font-size: 1.1em;
}
p.error {
color: #d06079;
}
@-webkit-keyframes dash {
0% {
stroke-dashoffset: 1000;
}
100% {
stroke-dashoffset: 0;
}
}
@keyframes dash {
0% {
stroke-dashoffset: 1000;
}
100% {
stroke-dashoffset: 0;
}
}

View File

@@ -19,7 +19,7 @@ body {
.content {
padding: 20px 16px;
margin: 0 auto
margin: 0 auto;
}
.header {
@@ -33,13 +33,20 @@ body {
justify-content: center;
}
.vertical-center {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
p {
padding-top: 20px;
width: 320px;
}
.header img {
margin-right: 16px
margin-right: 16px;
}
.group {
@@ -62,7 +69,8 @@ input:focus {
outline: none;
}
input:focus ~ label, input:valid ~ label {
input:focus ~ label,
input:valid ~ label {
top: -14px;
font-size: 12px;
color: #03a9f4;

65
web/error.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Home Assistant</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,user-scalable=no" />
<link href="assets/style.css" rel="stylesheet" />
<link href="assets/error.css" rel="stylesheet" />
</head>
<body>
<div class="vertical-center">
<div class="content">
<div class="center">
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 130.2 130.2"
>
<circle
class="path circle"
fill="none"
stroke="#D06079"
stroke-width="6"
stroke-miterlimit="10"
cx="65.1"
cy="65.1"
r="62.1"
/>
<line
class="path line"
fill="none"
stroke="#D06079"
stroke-width="6"
stroke-linecap="round"
stroke-miterlimit="10"
x1="34.4"
y1="37.9"
x2="95.8"
y2="92.3"
/>
<line
class="path line"
fill="none"
stroke="#D06079"
stroke-width="6"
stroke-linecap="round"
stroke-miterlimit="10"
x1="95.8"
y1="38"
x2="34.4"
y2="92.2"
/>
</svg>
</div>
<div class="center">
<p class="error">
Home Assistant instance is not available, please check your
connection.
</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,19 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<head>
<title>Home Assistant</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,user-scalable=no">
<link href="assets/style.css" rel="stylesheet">
<link href="assets/checkmark.css" rel="stylesheet">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,user-scalable=no" />
<link href="assets/style.css" rel="stylesheet" />
<link href="assets/checkmark.css" rel="stylesheet" />
<script>
const {ipcRenderer} = require('electron');
const { ipcRenderer } = require("electron");
ipcRenderer.send('ha-instance');
ipcRenderer.send("ha-instance");
ipcRenderer.on('ha-instance', function (event, url) {
window.location.href = url
let showCheckmark = false;
ipcRenderer.on("ha-instance", function (event, url) {
if (showCheckmark) {
document
.getElementById("check-wrapper")
.addEventListener(
"animationend",
() => (window.location.href = url)
);
} else window.location.href = url;
});
function isValidUrl(string) {
@@ -26,34 +34,36 @@
}
function checkUrl() {
let url = document.getElementById('url').value;
const url = document.getElementById("url").value;
if (!isValidUrl(url)) {
return
return;
}
let request = new XMLHttpRequest();
request.open('GET', url + '/auth/providers', true);
request.onreadystatechange = function () {
if (request.status === 200) {
document.getElementById('check-wrapper').style.display = 'block';
document.getElementById('url-wrapper').style.display = 'none';
ipcRenderer.send('ha-instance', {url: url, name: JSON.parse(request.responseText)[0].name});
setTimeout(function () {
window.location.href = url
}, 1000)
fetch(url + "/auth/providers")
.then((response) => {
if (response.ok) {
document.getElementById("url").value = url;
document.getElementById("url").disabled = true;
document.getElementById("check-wrapper").style.display = "block";
document.getElementById("url-wrapper").style.display = "none";
showCheckmark = true;
ipcRenderer.send("ha-instance", url);
}
};
request.send();
})
.catch((err) => {});
}
</script>
</head>
</head>
<body>
<div class="content">
<div class="center header"><img src="assets/favicon.png" height="52"> Home Assistant</div>
<body>
<div class="content">
<div class="center header">
<img src="assets/favicon.png" height="52" /> Home Assistant
</div>
<div class="center">
<p>Please enter your Home Assistant URL in the field below:</p></div>
<p>Please enter your Home Assistant URL in the field below:</p>
</div>
<div class="center">
<div id="check-wrapper" class="success-checkmark">
<div class="check-icon">
@@ -64,16 +74,20 @@
</div>
</div>
<div id="url-wrapper" class="group">
<input type="url" required="required" id="url" onkeyup="checkUrl()"/>
<input type="url" required="required" id="url" onkeyup="checkUrl()" />
<span class="highlight"></span>
<span class="bar"></span>
<label>Home Assistant URL</label>
</div>
</div>
<div class="center">
<p><small class="grey">If the entered URL directs to a working Home Assistant instance, you will be forwarded to the login page automatically.</small></p>
<p>
<small class="grey"
>If the entered URL directs to a working Home Assistant instance,
you will be forwarded to the login page automatically.</small
>
</p>
</div>
</div>
</body>
</div>
</body>
</html>