Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64f162440f | |||
| e30e0395d3 | |||
| d1013c87a1 | |||
| c3c3fc83e3 | |||
| 14ce5c728d | |||
| 60f56a2dea | |||
| 099cc252fe | |||
| 3a6be50e31 |
@@ -0,0 +1,37 @@
|
|||||||
|
name: Deploy GitHub Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
paths:
|
||||||
|
- 'docs/**'
|
||||||
|
- '.github/workflows/deploy-pages.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: pages
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Configure Pages
|
||||||
|
uses: actions/configure-pages@v5
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: docs
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# build-kit.ps1 — Build the Alta Proxy Tool Kit zip for distribution
|
||||||
|
# Usage: powershell -ExecutionPolicy Bypass -File build-kit.ps1
|
||||||
|
#
|
||||||
|
# Produces: dist/AltaProxyToolKit.zip containing:
|
||||||
|
# - AltaCameraProxy-<version>-portable.exe
|
||||||
|
# - aware-cam-proxy.exe
|
||||||
|
# - chrome-extension/ (folder)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# Read version from package.json
|
||||||
|
$pkg = Get-Content "package.json" -Raw | ConvertFrom-Json
|
||||||
|
$version = $pkg.version
|
||||||
|
Write-Host "Building Alta Proxy Tool Kit v$version" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Step 1: Build the Electron portable exe
|
||||||
|
Write-Host "`n[1/4] Building Electron app..." -ForegroundColor Yellow
|
||||||
|
npm run build
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host "Build failed!" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$portableExe = "dist\AltaCameraProxy-$version-portable.exe"
|
||||||
|
if (-not (Test-Path $portableExe)) {
|
||||||
|
Write-Host "Expected output not found: $portableExe" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Host " Built: $portableExe" -ForegroundColor Green
|
||||||
|
|
||||||
|
# Step 2: Verify aware-cam-proxy.exe exists
|
||||||
|
Write-Host "`n[2/4] Checking for aware-cam-proxy.exe..." -ForegroundColor Yellow
|
||||||
|
if (-not (Test-Path "aware-cam-proxy.exe")) {
|
||||||
|
Write-Host "aware-cam-proxy.exe not found in project root!" -ForegroundColor Red
|
||||||
|
Write-Host "Place aware-cam-proxy.exe in the project root and try again." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Host " Found: aware-cam-proxy.exe" -ForegroundColor Green
|
||||||
|
|
||||||
|
# Step 3: Verify chrome-extension folder exists
|
||||||
|
Write-Host "`n[3/4] Checking for chrome-extension/..." -ForegroundColor Yellow
|
||||||
|
if (-not (Test-Path "chrome-extension\manifest.json")) {
|
||||||
|
Write-Host "chrome-extension/ folder not found or missing manifest.json!" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Host " Found: chrome-extension/" -ForegroundColor Green
|
||||||
|
|
||||||
|
# Step 4: Create the kit zip
|
||||||
|
Write-Host "`n[4/4] Creating AltaProxyToolKit.zip..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$kitDir = "dist\AltaProxyToolKit"
|
||||||
|
$zipPath = "dist\AltaProxyToolKit.zip"
|
||||||
|
|
||||||
|
# Clean previous kit
|
||||||
|
if (Test-Path $kitDir) { Remove-Item $kitDir -Recurse -Force }
|
||||||
|
if (Test-Path $zipPath) { Remove-Item $zipPath -Force }
|
||||||
|
|
||||||
|
# Assemble kit contents
|
||||||
|
New-Item -ItemType Directory -Path $kitDir | Out-Null
|
||||||
|
Copy-Item $portableExe "$kitDir\AltaCameraProxy.exe"
|
||||||
|
Copy-Item "aware-cam-proxy.exe" "$kitDir\aware-cam-proxy.exe"
|
||||||
|
Copy-Item "chrome-extension" "$kitDir\chrome-extension" -Recurse
|
||||||
|
|
||||||
|
# Create zip
|
||||||
|
Compress-Archive -Path "$kitDir\*" -DestinationPath $zipPath -Force
|
||||||
|
|
||||||
|
# Clean up temp directory
|
||||||
|
Remove-Item $kitDir -Recurse -Force
|
||||||
|
|
||||||
|
$zipSize = [math]::Round((Get-Item $zipPath).Length / 1MB, 1)
|
||||||
|
Write-Host "`nKit ready: $zipPath ($zipSize MB)" -ForegroundColor Green
|
||||||
|
Write-Host "Upload this file as a release asset named 'AltaProxyToolKit.zip'" -ForegroundColor Cyan
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
+341
@@ -0,0 +1,341 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- GitHub Pages rebuild marker: 2026-05-22 -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Alta Proxy Tool</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg-primary: #1E1E1E;
|
||||||
|
--bg-secondary: #2D2D30;
|
||||||
|
--border: #3C3C3C;
|
||||||
|
--text-primary: #E0E0E0;
|
||||||
|
--text-secondary: #999999;
|
||||||
|
--accent-primary: #0E7AFE;
|
||||||
|
--accent-primary-hover: #0A5FD9;
|
||||||
|
--card-bg: #2D2D30;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--accent-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
.header {
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
padding: 16px 0;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-brand {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-brand img {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-brand span {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-link {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-link:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero */
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
text-align: center;
|
||||||
|
padding: 100px 0 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-icon {
|
||||||
|
width: 96px;
|
||||||
|
height: 96px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero .tagline {
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 40px;
|
||||||
|
max-width: 500px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-download {
|
||||||
|
display: inline-block;
|
||||||
|
background: var(--accent-primary);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 16px 40px;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-download:hover {
|
||||||
|
background: var(--accent-primary-hover);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-note {
|
||||||
|
margin-top: 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kit contents */
|
||||||
|
.kit-info {
|
||||||
|
padding: 48px 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kit-info h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kit-contents {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kit-item {
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px 28px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kit-item strong {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kit-item span {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup */
|
||||||
|
.setup {
|
||||||
|
padding: 48px 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-steps {
|
||||||
|
list-style: none;
|
||||||
|
max-width: 480px;
|
||||||
|
margin: 0 auto;
|
||||||
|
counter-reset: step;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-steps li {
|
||||||
|
counter-increment: step;
|
||||||
|
padding: 12px 0 12px 44px;
|
||||||
|
position: relative;
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-steps li + li {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-steps li::before {
|
||||||
|
content: counter(step);
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 12px;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background: var(--accent-primary);
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-steps code {
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 1px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-note {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.footer {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
padding: 24px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.hero {
|
||||||
|
padding: 60px 0 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero .tagline {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-download {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 12px 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kit-contents {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kit-item {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 280px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header class="header">
|
||||||
|
<div class="container">
|
||||||
|
<div class="header-brand">
|
||||||
|
<img src="icon.png" alt="Alta Proxy Tool">
|
||||||
|
<span>Alta Proxy Tool</span>
|
||||||
|
</div>
|
||||||
|
<a href="https://github.com/PageZ948/Alta-Proxy-Tool" class="header-link">GitHub</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<div class="hero">
|
||||||
|
<img src="icon.png" alt="" class="hero-icon">
|
||||||
|
<h1>Alta Proxy Tool</h1>
|
||||||
|
<a href="https://github.com/PageZ948/Alta-Proxy-Tool/releases/latest/download/AltaProxyToolKit.zip" class="btn-download">Download Kit for Windows</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="setup">
|
||||||
|
<h2>Setup</h2>
|
||||||
|
<ol class="setup-steps">
|
||||||
|
<li>Extract the zip to any folder</li>
|
||||||
|
<li>Load <code>chrome-extension/</code> in Chrome via <code>chrome://extensions</code> (Developer mode)</li>
|
||||||
|
<li>Log into your Alta deployment in Chrome</li>
|
||||||
|
<li>Click the extension icon and send cookies to the app</li>
|
||||||
|
<li>Run <strong>AltaCameraProxy.exe</strong> and start proxying</li>
|
||||||
|
</ol>
|
||||||
|
<p class="setup-note">Requires Windows 10+, Google Chrome, and an Avigilon Alta account.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<a href="https://github.com/PageZ948/Alta-Proxy-Tool">Alta Proxy Tool on GitHub</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -13,6 +13,16 @@ let cookieServer = null;
|
|||||||
const COOKIE_SERVER_PORT = 18247;
|
const COOKIE_SERVER_PORT = 18247;
|
||||||
const COOKIE_SERVER_TOKEN = 'apt-local-bridge-token';
|
const COOKIE_SERVER_TOKEN = 'apt-local-bridge-token';
|
||||||
|
|
||||||
|
// Get the directory where the user-facing executable resides.
|
||||||
|
// In portable builds, __dirname points to a temp extraction directory,
|
||||||
|
// so we use the actual .exe location instead.
|
||||||
|
function getAppDirectory() {
|
||||||
|
if (app.isPackaged) {
|
||||||
|
return path.dirname(process.env.PORTABLE_EXECUTABLE_FILE || app.getPath('exe'));
|
||||||
|
}
|
||||||
|
return __dirname;
|
||||||
|
}
|
||||||
|
|
||||||
// Sanitize strings before embedding in batch files to prevent command injection
|
// Sanitize strings before embedding in batch files to prevent command injection
|
||||||
function sanitizeBatchInput(input) {
|
function sanitizeBatchInput(input) {
|
||||||
if (typeof input !== 'string') return '';
|
if (typeof input !== 'string') return '';
|
||||||
@@ -208,6 +218,33 @@ ipcMain.handle('api-get-devices', async (event, { deploymentUrl, cookies }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('api-get-device-sites', async (event, { deploymentUrl, cookies }) => {
|
||||||
|
try {
|
||||||
|
const sitesUrl = `${deploymentUrl}/api/v1/deviceSites`;
|
||||||
|
|
||||||
|
const axiosInstance = axios.create({
|
||||||
|
timeout: 10000,
|
||||||
|
headers: {
|
||||||
|
'Cookie': cookies ? cookies.join('; ') : ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await axiosInstance.get(sitesUrl);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
sites: response.data
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get device sites error:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
sites: [],
|
||||||
|
message: error.response?.data?.message || error.message || 'Failed to get device sites'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle('api-get-auth-info', async (event, { deploymentUrl, cookies }) => {
|
ipcMain.handle('api-get-auth-info', async (event, { deploymentUrl, cookies }) => {
|
||||||
try {
|
try {
|
||||||
const authUrl = `${deploymentUrl}/api/v1/auth`;
|
const authUrl = `${deploymentUrl}/api/v1/auth`;
|
||||||
@@ -238,7 +275,7 @@ ipcMain.handle('api-get-auth-info', async (event, { deploymentUrl, cookies }) =>
|
|||||||
ipcMain.handle('camera-proxy-cookie-launch', async (event, { deploymentUrl, cookieKey, deviceUuid }) => {
|
ipcMain.handle('camera-proxy-cookie-launch', async (event, { deploymentUrl, cookieKey, deviceUuid }) => {
|
||||||
try {
|
try {
|
||||||
// Path to the cookie-based camera proxy executable
|
// Path to the cookie-based camera proxy executable
|
||||||
const proxyExePath = path.join(__dirname, 'aware-cam-proxy.exe');
|
const proxyExePath = path.join(getAppDirectory(), 'aware-cam-proxy.exe');
|
||||||
|
|
||||||
// Check if the executable exists
|
// Check if the executable exists
|
||||||
if (!fs.existsSync(proxyExePath)) {
|
if (!fs.existsSync(proxyExePath)) {
|
||||||
@@ -502,7 +539,7 @@ ipcMain.handle('download-and-install-update', async (event, { downloadUrl }) =>
|
|||||||
try {
|
try {
|
||||||
// Determine the path to the currently running executable
|
// Determine the path to the currently running executable
|
||||||
const currentExePath = process.env.PORTABLE_EXECUTABLE_FILE || app.getPath('exe');
|
const currentExePath = process.env.PORTABLE_EXECUTABLE_FILE || app.getPath('exe');
|
||||||
const currentDir = path.dirname(currentExePath);
|
const currentDir = getAppDirectory();
|
||||||
const currentExeName = path.basename(currentExePath);
|
const currentExeName = path.basename(currentExePath);
|
||||||
|
|
||||||
// Check write permission on the app directory
|
// Check write permission on the app directory
|
||||||
|
|||||||
Generated
+1
-615
@@ -15,9 +15,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^28.0.0",
|
"electron": "^28.0.0",
|
||||||
"electron-builder": "^26.4.0",
|
"electron-builder": "^26.4.0",
|
||||||
"electron-packager": "^17.1.2",
|
"electron-packager": "^17.1.2"
|
||||||
"png-to-ico": "^3.0.1",
|
|
||||||
"sharp": "^0.34.5"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@develar/schema-utils": {
|
"node_modules/@develar/schema-utils": {
|
||||||
@@ -459,507 +457,6 @@
|
|||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
|
||||||
"version": "1.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
|
|
||||||
"integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": "^2.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/colour": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-darwin-arm64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-darwin-x64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-darwin-x64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-ppc64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-riscv64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
|
|
||||||
"cpu": [
|
|
||||||
"riscv64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
|
|
||||||
"cpu": [
|
|
||||||
"s390x"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-arm": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-arm": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-arm64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-arm64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-ppc64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-ppc64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-riscv64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
|
|
||||||
"cpu": [
|
|
||||||
"riscv64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-riscv64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-s390x": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
|
|
||||||
"cpu": [
|
|
||||||
"s390x"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-s390x": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linux-x64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linux-x64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-wasm32": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
|
|
||||||
"cpu": [
|
|
||||||
"wasm32"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@emnapi/runtime": "^1.7.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-win32-arm64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-win32-ia32": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
|
|
||||||
"cpu": [
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@img/sharp-win32-x64": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@isaacs/balanced-match": {
|
"node_modules/@isaacs/balanced-match": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
||||||
@@ -5096,51 +4593,6 @@
|
|||||||
"node": ">=10.4.0"
|
"node": ">=10.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/png-to-ico": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/png-to-ico/-/png-to-ico-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-S8BOAoaGd9gT5uaemQ62arIY3Jzco7Uc7LwUTqRyqJDTsKqOAiyfyN4dSdT0D+Zf8XvgztgpRbM5wnQd7EgYwg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "^22.10.3",
|
|
||||||
"minimist": "^1.2.8",
|
|
||||||
"pngjs": "^7.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"png-to-ico": "bin/cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/png-to-ico/node_modules/@types/node": {
|
|
||||||
"version": "22.19.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.10.tgz",
|
|
||||||
"integrity": "sha512-tF5VOugLS/EuDlTBijk0MqABfP8UxgYazTLo3uIn3b4yJgg26QRbVYJYsDtHrjdDUIRfP70+VfhTTc+CE1yskw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"undici-types": "~6.21.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/png-to-ico/node_modules/undici-types": {
|
|
||||||
"version": "6.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
|
||||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/pngjs": {
|
|
||||||
"version": "7.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
|
|
||||||
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.19.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postject": {
|
"node_modules/postject": {
|
||||||
"version": "1.0.0-alpha.6",
|
"version": "1.0.0-alpha.6",
|
||||||
"resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz",
|
"resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz",
|
||||||
@@ -5522,64 +4974,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sharp": {
|
|
||||||
"version": "0.34.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
|
||||||
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"@img/colour": "^1.0.0",
|
|
||||||
"detect-libc": "^2.1.2",
|
|
||||||
"semver": "^7.7.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/libvips"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@img/sharp-darwin-arm64": "0.34.5",
|
|
||||||
"@img/sharp-darwin-x64": "0.34.5",
|
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.2.4",
|
|
||||||
"@img/sharp-libvips-darwin-x64": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linux-arm": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linux-arm64": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linux-ppc64": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linux-riscv64": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linux-s390x": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linux-x64": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
|
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
|
|
||||||
"@img/sharp-linux-arm": "0.34.5",
|
|
||||||
"@img/sharp-linux-arm64": "0.34.5",
|
|
||||||
"@img/sharp-linux-ppc64": "0.34.5",
|
|
||||||
"@img/sharp-linux-riscv64": "0.34.5",
|
|
||||||
"@img/sharp-linux-s390x": "0.34.5",
|
|
||||||
"@img/sharp-linux-x64": "0.34.5",
|
|
||||||
"@img/sharp-linuxmusl-arm64": "0.34.5",
|
|
||||||
"@img/sharp-linuxmusl-x64": "0.34.5",
|
|
||||||
"@img/sharp-wasm32": "0.34.5",
|
|
||||||
"@img/sharp-win32-arm64": "0.34.5",
|
|
||||||
"@img/sharp-win32-ia32": "0.34.5",
|
|
||||||
"@img/sharp-win32-x64": "0.34.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sharp/node_modules/semver": {
|
|
||||||
"version": "7.7.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
|
||||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"bin": {
|
|
||||||
"semver": "bin/semver.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
@@ -6168,14 +5562,6 @@
|
|||||||
"utf8-byte-length": "^1.0.1"
|
"utf8-byte-length": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tslib": {
|
|
||||||
"version": "2.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
|
||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "0BSD",
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"node_modules/type-fest": {
|
"node_modules/type-fest": {
|
||||||
"version": "0.13.1",
|
"version": "0.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
||||||
|
|||||||
+5
-6
@@ -8,6 +8,7 @@
|
|||||||
"dev": "electron . --dev",
|
"dev": "electron . --dev",
|
||||||
"build": "electron-builder --win --publish=never",
|
"build": "electron-builder --win --publish=never",
|
||||||
"build-test": "electron-builder --win --dir",
|
"build-test": "electron-builder --win --dir",
|
||||||
|
"build-kit": "powershell -ExecutionPolicy Bypass -File build-kit.ps1",
|
||||||
"prebuild": "echo Checking build requirements..."
|
"prebuild": "echo Checking build requirements..."
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
@@ -18,13 +19,13 @@
|
|||||||
},
|
},
|
||||||
"win": {
|
"win": {
|
||||||
"target": "portable",
|
"target": "portable",
|
||||||
"icon": "assets/icon.png"
|
"icon": "assets/icon.png",
|
||||||
|
"signAndEditExecutable": false
|
||||||
},
|
},
|
||||||
"portable": {
|
"portable": {
|
||||||
"artifactName": "AltaCameraProxy-${version}-portable.exe"
|
"artifactName": "AltaCameraProxy-${version}-portable.exe"
|
||||||
},
|
},
|
||||||
"afterSign": false,
|
"forceCodeSigning": false
|
||||||
"afterAllArtifactBuild": false
|
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"electron",
|
"electron",
|
||||||
@@ -37,9 +38,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^28.0.0",
|
"electron": "^28.0.0",
|
||||||
"electron-builder": "^26.4.0",
|
"electron-builder": "^26.4.0",
|
||||||
"electron-packager": "^17.1.2",
|
"electron-packager": "^17.1.2"
|
||||||
"png-to-ico": "^3.0.1",
|
|
||||||
"sharp": "^0.34.5"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const { contextBridge, ipcRenderer } = require('electron');
|
|||||||
// the ipcRenderer without exposing the entire object
|
// the ipcRenderer without exposing the entire object
|
||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
getDevices: (params) => ipcRenderer.invoke('api-get-devices', params),
|
getDevices: (params) => ipcRenderer.invoke('api-get-devices', params),
|
||||||
|
getDeviceSites: (params) => ipcRenderer.invoke('api-get-device-sites', params),
|
||||||
getAuthInfo: (params) => ipcRenderer.invoke('api-get-auth-info', params),
|
getAuthInfo: (params) => ipcRenderer.invoke('api-get-auth-info', params),
|
||||||
|
|
||||||
// Camera proxy functionality
|
// Camera proxy functionality
|
||||||
|
|||||||
+177
-29
@@ -37,6 +37,8 @@ const updateLaterBtn = document.getElementById('updateLaterBtn');
|
|||||||
let selectedDevice = null;
|
let selectedDevice = null;
|
||||||
let activeCookieProxyConnections = new Map(); // Track cookie-based proxy connections
|
let activeCookieProxyConnections = new Map(); // Track cookie-based proxy connections
|
||||||
let allDevices = []; // Store all devices for search functionality
|
let allDevices = []; // Store all devices for search functionality
|
||||||
|
let allSites = {}; // Store site id → site name mapping
|
||||||
|
let collapsedSites = new Set(); // Track which site groups are collapsed
|
||||||
let pendingUpdateInfo = null; // Store update info for install action
|
let pendingUpdateInfo = null; // Store update info for install action
|
||||||
|
|
||||||
// Event listeners
|
// Event listeners
|
||||||
@@ -66,6 +68,8 @@ function handleDisconnect() {
|
|||||||
selectedDevice = null;
|
selectedDevice = null;
|
||||||
activeCookieProxyConnections.clear();
|
activeCookieProxyConnections.clear();
|
||||||
allDevices = []; // Clear stored devices
|
allDevices = []; // Clear stored devices
|
||||||
|
allSites = {}; // Clear site data
|
||||||
|
collapsedSites.clear();
|
||||||
|
|
||||||
updateConnectionStatus(false);
|
updateConnectionStatus(false);
|
||||||
updateButtonStates();
|
updateButtonStates();
|
||||||
@@ -218,6 +222,28 @@ function updateButtonStates() {
|
|||||||
updateCookieProxyButtonStates();
|
updateCookieProxyButtonStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch device sites and build id → name map
|
||||||
|
async function fetchDeviceSites() {
|
||||||
|
try {
|
||||||
|
const result = await window.electronAPI.getDeviceSites({
|
||||||
|
deploymentUrl: sessionData.deploymentUrl,
|
||||||
|
cookies: sessionData.cookies
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.success && Array.isArray(result.sites)) {
|
||||||
|
allSites = {};
|
||||||
|
result.sites.forEach(site => {
|
||||||
|
if (site.id) {
|
||||||
|
allSites[site.id] = site.name || 'Unnamed Site';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Could not fetch device sites:', error.message);
|
||||||
|
allSites = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle get devices (now called automatically)
|
// Handle get devices (now called automatically)
|
||||||
async function handleGetDevices() {
|
async function handleGetDevices() {
|
||||||
if (!sessionData.isConnected) {
|
if (!sessionData.isConnected) {
|
||||||
@@ -229,14 +255,18 @@ async function handleGetDevices() {
|
|||||||
clearDeviceList();
|
clearDeviceList();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await window.electronAPI.getDevices({
|
// Fetch devices and sites in parallel
|
||||||
|
const [devicesResult] = await Promise.all([
|
||||||
|
window.electronAPI.getDevices({
|
||||||
deploymentUrl: sessionData.deploymentUrl,
|
deploymentUrl: sessionData.deploymentUrl,
|
||||||
cookies: sessionData.cookies
|
cookies: sessionData.cookies
|
||||||
});
|
}),
|
||||||
|
fetchDeviceSites()
|
||||||
|
]);
|
||||||
|
|
||||||
if (result.success) {
|
if (devicesResult.success) {
|
||||||
// Filter devices to only show non-cloud cameras (localStorage = false)
|
// Filter devices to only show non-cloud cameras (localStorage = false)
|
||||||
const filteredDevices = result.devices.filter(device => {
|
const filteredDevices = devicesResult.devices.filter(device => {
|
||||||
// Check if device has capabilities and localStorage property
|
// Check if device has capabilities and localStorage property
|
||||||
if (device.capabilities && device.capabilities.localStorage !== undefined) {
|
if (device.capabilities && device.capabilities.localStorage !== undefined) {
|
||||||
// Only show devices where localStorage is false (non-cloud cameras)
|
// Only show devices where localStorage is false (non-cloud cameras)
|
||||||
@@ -246,11 +276,15 @@ async function handleGetDevices() {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
const totalDevices = result.devices.length;
|
const totalDevices = devicesResult.devices.length;
|
||||||
const filteredCount = filteredDevices.length;
|
const filteredCount = filteredDevices.length;
|
||||||
const cloudDevicesHidden = totalDevices - filteredCount;
|
const cloudDevicesHidden = totalDevices - filteredCount;
|
||||||
|
|
||||||
|
const siteCount = Object.keys(allSites).length;
|
||||||
let statusMessage = `Found ${filteredCount} local camera${filteredCount !== 1 ? 's' : ''}`;
|
let statusMessage = `Found ${filteredCount} local camera${filteredCount !== 1 ? 's' : ''}`;
|
||||||
|
if (siteCount > 0) {
|
||||||
|
statusMessage += ` across ${siteCount} site${siteCount !== 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
if (cloudDevicesHidden > 0) {
|
if (cloudDevicesHidden > 0) {
|
||||||
statusMessage += ` (${cloudDevicesHidden} cloud camera${cloudDevicesHidden !== 1 ? 's' : ''} hidden)`;
|
statusMessage += ` (${cloudDevicesHidden} cloud camera${cloudDevicesHidden !== 1 ? 's' : ''} hidden)`;
|
||||||
}
|
}
|
||||||
@@ -261,7 +295,7 @@ async function handleGetDevices() {
|
|||||||
allDevices = filteredDevices;
|
allDevices = filteredDevices;
|
||||||
displayDevices(filteredDevices);
|
displayDevices(filteredDevices);
|
||||||
} else {
|
} else {
|
||||||
showStatus(deviceStatus, `Failed to get devices: ${result.message}`, 'error');
|
showStatus(deviceStatus, `Failed to get devices: ${devicesResult.message}`, 'error');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Get devices error:', error);
|
console.error('Get devices error:', error);
|
||||||
@@ -347,25 +381,73 @@ function handleDeviceSearch() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter devices based on search term
|
// Filter devices based on search term (includes site name)
|
||||||
const filteredDevices = allDevices.filter(device => {
|
const filteredDevices = allDevices.filter(device => {
|
||||||
const deviceName = (device.name || '').toLowerCase();
|
const deviceName = (device.name || '').toLowerCase();
|
||||||
const deviceId = (device.guid || device.id || '').toLowerCase();
|
const deviceId = (device.guid || device.id || '').toLowerCase();
|
||||||
const deviceType = (device.type || '').toLowerCase();
|
const deviceType = (device.type || '').toLowerCase();
|
||||||
const deviceModel = (device.model || '').toLowerCase();
|
const deviceModel = (device.model || '').toLowerCase();
|
||||||
const deviceIp = (device.ipAddress || '').toLowerCase();
|
const deviceIp = (device.ipAddress || '').toLowerCase();
|
||||||
|
const siteName = (device.server_group_id && allSites[device.server_group_id] || '').toLowerCase();
|
||||||
|
|
||||||
return deviceName.includes(searchTerm) ||
|
return deviceName.includes(searchTerm) ||
|
||||||
deviceId.includes(searchTerm) ||
|
deviceId.includes(searchTerm) ||
|
||||||
deviceType.includes(searchTerm) ||
|
deviceType.includes(searchTerm) ||
|
||||||
deviceModel.includes(searchTerm) ||
|
deviceModel.includes(searchTerm) ||
|
||||||
deviceIp.includes(searchTerm);
|
deviceIp.includes(searchTerm) ||
|
||||||
|
siteName.includes(searchTerm);
|
||||||
});
|
});
|
||||||
|
|
||||||
displayDevices(filteredDevices);
|
displayDevices(filteredDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display devices in the UI
|
// Group devices by their site using server_group_id → allSites mapping
|
||||||
|
function groupDevicesBySite(devices) {
|
||||||
|
const groups = {};
|
||||||
|
const ungrouped = [];
|
||||||
|
|
||||||
|
devices.forEach(device => {
|
||||||
|
const siteId = device.server_group_id;
|
||||||
|
const siteName = siteId && allSites[siteId] ? allSites[siteId] : null;
|
||||||
|
|
||||||
|
if (siteName) {
|
||||||
|
if (!groups[siteId]) {
|
||||||
|
groups[siteId] = { name: siteName, devices: [] };
|
||||||
|
}
|
||||||
|
groups[siteId].devices.push(device);
|
||||||
|
} else {
|
||||||
|
ungrouped.push(device);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { groups, ungrouped };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a device item DOM element
|
||||||
|
function createDeviceItem(device, index) {
|
||||||
|
const deviceItem = document.createElement('div');
|
||||||
|
deviceItem.className = 'device-item';
|
||||||
|
deviceItem.dataset.deviceIndex = index;
|
||||||
|
deviceItem.dataset.deviceId = device.guid || device.id;
|
||||||
|
|
||||||
|
const status = getDeviceStatus(device);
|
||||||
|
const deviceId = device.guid || device.id;
|
||||||
|
const isCookieProxyActive = activeCookieProxyConnections.has(deviceId);
|
||||||
|
|
||||||
|
if (isCookieProxyActive) {
|
||||||
|
deviceItem.classList.add('cookie-proxy-active');
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceItem.innerHTML = `
|
||||||
|
<div class="device-name">${escapeHtml(device.name || 'Unnamed Device')}</div>
|
||||||
|
<div class="device-status-dot ${status.isOnline ? 'online' : 'offline'}"></div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
deviceItem.addEventListener('click', () => selectDevice(device, deviceItem));
|
||||||
|
return deviceItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display devices in the UI, grouped by site
|
||||||
function displayDevices(devices) {
|
function displayDevices(devices) {
|
||||||
clearDeviceList();
|
clearDeviceList();
|
||||||
|
|
||||||
@@ -376,33 +458,99 @@ function displayDevices(devices) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasSites = Object.keys(allSites).length > 0;
|
||||||
|
|
||||||
|
// If no sites were fetched, fall back to flat list
|
||||||
|
if (!hasSites) {
|
||||||
devices.forEach((device, index) => {
|
devices.forEach((device, index) => {
|
||||||
const deviceItem = document.createElement('div');
|
deviceList.appendChild(createDeviceItem(device, index));
|
||||||
deviceItem.className = 'device-item';
|
});
|
||||||
deviceItem.dataset.deviceIndex = index;
|
updateCookieProxyButtonStates();
|
||||||
deviceItem.dataset.deviceId = device.guid || device.id;
|
return;
|
||||||
|
|
||||||
const deviceStatus = getDeviceStatus(device);
|
|
||||||
const deviceId = device.guid || device.id;
|
|
||||||
const isCookieProxyActive = activeCookieProxyConnections.has(deviceId);
|
|
||||||
|
|
||||||
// Add cookie-proxy-active class if this device has an active cookie connection
|
|
||||||
if (isCookieProxyActive) {
|
|
||||||
deviceItem.classList.add('cookie-proxy-active');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceItem.innerHTML = `
|
const { groups, ungrouped } = groupDevicesBySite(devices);
|
||||||
<div class="device-name">${escapeHtml(device.name || 'Unnamed Device')}</div>
|
|
||||||
<div class="device-status-dot ${deviceStatus.isOnline ? 'online' : 'offline'}"></div>
|
// Sort site groups alphabetically by name
|
||||||
|
const sortedSiteIds = Object.keys(groups).sort((a, b) =>
|
||||||
|
groups[a].name.localeCompare(groups[b].name)
|
||||||
|
);
|
||||||
|
|
||||||
|
let globalIndex = 0;
|
||||||
|
|
||||||
|
sortedSiteIds.forEach(siteId => {
|
||||||
|
const group = groups[siteId];
|
||||||
|
const isCollapsed = collapsedSites.has(siteId);
|
||||||
|
|
||||||
|
// Site header
|
||||||
|
const siteHeader = document.createElement('div');
|
||||||
|
siteHeader.className = 'site-group-header' + (isCollapsed ? ' collapsed' : '');
|
||||||
|
siteHeader.innerHTML = `
|
||||||
|
<span class="site-group-arrow">${isCollapsed ? '\u25B6' : '\u25BC'}</span>
|
||||||
|
<span class="site-group-name">${escapeHtml(group.name)}</span>
|
||||||
|
<span class="site-group-count">${group.devices.length}</span>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Add click handler for device selection
|
siteHeader.addEventListener('click', () => {
|
||||||
deviceItem.addEventListener('click', () => selectDevice(device, deviceItem));
|
if (collapsedSites.has(siteId)) {
|
||||||
|
collapsedSites.delete(siteId);
|
||||||
deviceList.appendChild(deviceItem);
|
} else {
|
||||||
|
collapsedSites.add(siteId);
|
||||||
|
}
|
||||||
|
// Re-render with current search filter
|
||||||
|
const searchTerm = deviceSearch.value.toLowerCase().trim();
|
||||||
|
if (searchTerm) {
|
||||||
|
handleDeviceSearch();
|
||||||
|
} else {
|
||||||
|
displayDevices(allDevices);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update cookie proxy button states after displaying devices
|
deviceList.appendChild(siteHeader);
|
||||||
|
|
||||||
|
// Device items (hidden if collapsed)
|
||||||
|
if (!isCollapsed) {
|
||||||
|
group.devices.forEach(device => {
|
||||||
|
deviceList.appendChild(createDeviceItem(device, globalIndex++));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ungrouped devices at the bottom
|
||||||
|
if (ungrouped.length > 0) {
|
||||||
|
if (sortedSiteIds.length > 0) {
|
||||||
|
const ungroupedHeader = document.createElement('div');
|
||||||
|
ungroupedHeader.className = 'site-group-header' + (collapsedSites.has('__ungrouped') ? ' collapsed' : '');
|
||||||
|
ungroupedHeader.innerHTML = `
|
||||||
|
<span class="site-group-arrow">${collapsedSites.has('__ungrouped') ? '\u25B6' : '\u25BC'}</span>
|
||||||
|
<span class="site-group-name">Ungrouped</span>
|
||||||
|
<span class="site-group-count">${ungrouped.length}</span>
|
||||||
|
`;
|
||||||
|
|
||||||
|
ungroupedHeader.addEventListener('click', () => {
|
||||||
|
if (collapsedSites.has('__ungrouped')) {
|
||||||
|
collapsedSites.delete('__ungrouped');
|
||||||
|
} else {
|
||||||
|
collapsedSites.add('__ungrouped');
|
||||||
|
}
|
||||||
|
const searchTerm = deviceSearch.value.toLowerCase().trim();
|
||||||
|
if (searchTerm) {
|
||||||
|
handleDeviceSearch();
|
||||||
|
} else {
|
||||||
|
displayDevices(allDevices);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceList.appendChild(ungroupedHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!collapsedSites.has('__ungrouped') || sortedSiteIds.length === 0) {
|
||||||
|
ungrouped.forEach(device => {
|
||||||
|
deviceList.appendChild(createDeviceItem(device, globalIndex++));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateCookieProxyButtonStates();
|
updateCookieProxyButtonStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+47
@@ -167,6 +167,53 @@ body {
|
|||||||
box-shadow: 0 0 6px rgba(244, 67, 54, 0.6);
|
box-shadow: 0 0 6px rgba(244, 67, 54, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Site Group Headers */
|
||||||
|
.site-group-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
user-select: none;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-group-header:hover {
|
||||||
|
background: var(--hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-group-arrow {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
width: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-group-name {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-group-count {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.placeholder-text {
|
.placeholder-text {
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|||||||
Reference in New Issue
Block a user