Skip to content

Commit

Permalink
app build
Browse files Browse the repository at this point in the history
  • Loading branch information
killerwolf committed Sep 14, 2024
1 parent 3cc9939 commit 0edac8a
Show file tree
Hide file tree
Showing 7 changed files with 4,904 additions and 587 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build and Release

on:
push:
tags:
- 'v*'

jobs:
build:
runs-on: macos-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Build the app
run: npm run build

- name: Package the app
run: |
npx electron-builder --mac --publish=always
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 changes: 13 additions & 0 deletions build/entitlements.mac.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
</dict>
</plist>
92 changes: 72 additions & 20 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,86 @@
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
/>
<style>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.tab-content {
padding: 10px;
}
.nav-tabs {
margin-bottom: 0;
}
/* Add custom styles to make the app look more desktop-like */
.nav-tabs .nav-link {
border: none;
color: #007bff;
}
.nav-tabs .nav-link.active {
color: black;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container mt-4">
<h1 class="mb-4">Running Scripts</h1>

<!-- Filter Input -->
<div class="form-group">
<input type="text" id="filter-input" class="form-control" placeholder="Filter by name" />
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" href="#" id="tab-processes">Processes</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="tab-preferences">Preferences</a>
</li>
</ul>
<div class="tab-content">
<!-- Processes Tab -->
<div id="processes-tab">
<div class="form-group">
<input type="text" id="filter-input" class="form-control" placeholder="Filter by name" />
</div>
<table class="table table-striped" id="process-table">
<thead class="thead-dark">
<tr>
<th scope="col"></th>
<th scope="col">PID</th>
<th scope="col">Name</th>
<th scope="col">Command</th>
</tr>
</thead>
<tbody>
<!-- Process rows will be inserted here -->
</tbody>
</table>
</div>

<!-- Process Table -->
<table class="table table-striped" id="process-table">
<thead class="thead-dark">
<tr>
<th scope="col"></th>
<th scope="col">PID</th>
<th scope="col">Name</th>
<th scope="col">Command</th>
</tr>
</thead>
<tbody>
<!-- Process rows will be inserted here -->
</tbody>
</table>
<!-- Preferences Tab -->
<div id="preferences-tab" style="display: none;">
<div class="form-group">
<label>
<input type="checkbox" id="autoLaunch" /> Start at Login
</label>
</div>
<div class="form-group">
<label for="prefilterRegex">Prefilter Regular Expression:</label>
<input
type="text"
id="prefilterRegex"
class="form-control"
placeholder="e.g., node|python|bash"
/>
<small class="form-text text-muted">
Processes matching this regular expression will be displayed. Leave empty to show all processes.
</small>
</div>
<button id="savePreferences" class="btn btn-primary">Save</button>
</div>
</div>

<!-- Include Bootstrap JS (optional) -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>

<!-- Include renderer.js -->
<script src="renderer.js"></script>
</body>
</html>
139 changes: 98 additions & 41 deletions main.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
// main.js
import { app, BrowserWindow, ipcMain, Tray, Menu, nativeImage } from 'electron';
import { app, BrowserWindow, ipcMain, Tray, nativeImage, screen } from 'electron';
import path from 'path';
import psList from 'ps-list';
import { fileURLToPath } from 'url';
import Store from 'electron-store';

// Define __dirname manually in ES Modules
// Define __dirname in ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

let mainWindow;
let tray = null;
app.isQuitting = false; // Initialize isQuitting

// Initialize electron-store for preference persistence
const store = new Store();

// Load preferences from store or set default values
let preferences = store.get('preferences', {
autoLaunch: false,
prefilterRegex: '', // Default preferences
});

function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
width: 400, // Half the width
height: 500,
show: false, // Start hidden
frame: false, // Frameless window
resizable: false,
alwaysOnTop: true,
skipTaskbar: true,
transparent: true, // Optional: Make window transparent
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
Expand All @@ -25,80 +40,122 @@ function createWindow() {

mainWindow.loadFile('index.html');

// Hide the window instead of quitting when the close button is clicked
// Hide the window instead of closing when the close button is clicked
mainWindow.on('close', (event) => {
if (!app.isQuitting) {
event.preventDefault();
mainWindow.hide(); // Hide window instead of quitting
mainWindow.hide();
}
});
}

function toggleWindow() {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
showWindow();
}
}

function showWindow() {
// Get the position of the tray icon
const trayBounds = tray.getBounds();

// Get the display nearest to the tray icon
const display = screen.getDisplayNearestPoint({ x: trayBounds.x, y: trayBounds.y });

const windowBounds = mainWindow.getBounds();

// Calculate the x and y coordinates
let x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2));
let y;

if (process.platform === 'darwin') {
// For macOS, position the window below the tray icon
y = Math.round(display.bounds.y + trayBounds.height + 4);
} else {
// For Windows/Linux, position the window above the tray icon
y = Math.round(trayBounds.y - windowBounds.height);
}

// Ensure the window is within the bounds of the display
x = Math.max(display.bounds.x, Math.min(x, display.bounds.x + display.bounds.width - windowBounds.width));
y = Math.max(display.bounds.y, Math.min(y, display.bounds.y + display.bounds.height - windowBounds.height));

mainWindow.setPosition(x, y, false);
mainWindow.show();
mainWindow.focus();
}

function createTray() {
// Define the tray icon path and create a tray icon
const iconPath = path.join(__dirname, 'tray-icon.png');
const iconPath = path.join(__dirname, 'tray-icon.png'); // Provide your icon path
let trayIcon = nativeImage.createFromPath(iconPath);

// Adjust icon for macOS light/dark mode
// Resize the icon to 16x16 pixels
trayIcon = trayIcon.resize({ width: 16, height: 16 });

if (process.platform === 'darwin') {
trayIcon = trayIcon.resize({ width: 16, height: 16 });
trayIcon.setTemplateImage(true);
}

tray = new Tray(trayIcon);

// Define tray context menu with options to show the app or quit
const contextMenu = Menu.buildFromTemplate([
{
label: 'Show App',
click: () => {
mainWindow.show();
},
},
{
label: 'Quit',
click: () => {
app.isQuitting = true; // Set quitting flag
app.quit(); // Quit the app
},
},
]);

tray.setToolTip('Script Watcher');
tray.setContextMenu(contextMenu);

// Show the window when the tray icon is clicked
tray.on('click', () => {
mainWindow.show();
toggleWindow();
});
}

// Handle IPC events from the renderer process
// IPC handlers
ipcMain.handle('get-processes', async () => {
const processes = await psList();
return processes;
});

ipcMain.handle('get-preferences', () => {
return preferences;
});

ipcMain.on('save-preferences', (event, newPreferences) => {
preferences = { ...preferences, ...newPreferences };
store.set('preferences', preferences); // Save to store

// Apply settings
app.setLoginItemSettings({
openAtLogin: preferences.autoLaunch,
});
});

ipcMain.on('update-tray-tooltip', (event, numProcesses) => {
const tooltip = `Script Watcher - Monitoring ${numProcesses} process${numProcesses === 1 ? '' : 'es'}`;
tray.setToolTip(tooltip);
});

ipcMain.on('update-monitored-processes', (event, monitoredPIDs) => {
// You can handle monitored processes here if needed
});

app.whenReady().then(() => {
createTray(); // Create the tray icon
createWindow(); // Create the main window
createTray();
createWindow();

// Hide the app's dock icon on macOS
// On macOS, hide the dock icon
if (process.platform === 'darwin') {
app.dock.hide();
}
});

// Prevent the app from quitting when all windows are closed
app.on('before-quit', () => {
app.isQuitting = true;
});

app.on('window-all-closed', (event) => {
event.preventDefault(); // Override default quitting behavior
event.preventDefault(); // Prevent default behavior of quitting
});

// Re-create or show the window when the app is activated (macOS behavior)
app.on('activate', () => {
if (mainWindow) {
mainWindow.show(); // Show the window if it exists
showWindow();
} else {
createWindow(); // Create a new window if it doesn't exist
createWindow();
}
});
Loading

0 comments on commit 0edac8a

Please sign in to comment.