2023-11-04 03:56:27 +00:00
|
|
|
const { app, BrowserWindow, ipcMain, Tray, Menu, nativeImage, shell } = require('electron');
|
2023-09-06 19:04:18 +00:00
|
|
|
const todesktop = require("@todesktop/runtime");
|
2023-11-04 03:56:27 +00:00
|
|
|
const khojPackage = require('./package.json');
|
2023-09-06 19:04:18 +00:00
|
|
|
|
|
|
|
todesktop.init();
|
|
|
|
|
|
|
|
const fs = require('fs');
|
|
|
|
const {dialog} = require('electron');
|
|
|
|
|
|
|
|
const cron = require('cron').CronJob;
|
|
|
|
const axios = require('axios');
|
|
|
|
|
2023-11-09 21:34:27 +00:00
|
|
|
const KHOJ_URL = 'https://app.khoj.dev';
|
2023-09-06 19:04:18 +00:00
|
|
|
|
|
|
|
const Store = require('electron-store');
|
|
|
|
|
|
|
|
const validFileTypes = ['org', 'md', 'markdown', 'txt', 'html', 'xml', 'pdf']
|
|
|
|
|
|
|
|
const binaryFileTypes = ['pdf', 'png', 'jpg', 'jpeg']
|
|
|
|
|
|
|
|
const schema = {
|
|
|
|
files: {
|
|
|
|
type: 'array',
|
|
|
|
items: {
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
|
|
|
path: {
|
|
|
|
type: 'string'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
default: []
|
|
|
|
},
|
|
|
|
folders: {
|
|
|
|
type: 'array',
|
|
|
|
items: {
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
|
|
|
path: {
|
|
|
|
type: 'string'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
default: []
|
|
|
|
},
|
2023-10-26 19:33:03 +00:00
|
|
|
khojToken: {
|
|
|
|
type: 'string',
|
|
|
|
default: ''
|
|
|
|
},
|
2023-09-06 19:04:18 +00:00
|
|
|
hostURL: {
|
|
|
|
type: 'string',
|
|
|
|
default: KHOJ_URL
|
|
|
|
},
|
|
|
|
lastSync: {
|
|
|
|
type: 'array',
|
|
|
|
items: {
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
|
|
|
path: {
|
|
|
|
type: 'string'
|
|
|
|
},
|
|
|
|
datetime: {
|
|
|
|
type: 'string'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-11-09 21:34:27 +00:00
|
|
|
let syncing = false;
|
2023-09-06 19:04:18 +00:00
|
|
|
var state = {}
|
2023-10-12 01:12:12 +00:00
|
|
|
const store = new Store({ schema });
|
2023-09-06 19:04:18 +00:00
|
|
|
|
|
|
|
console.log(store);
|
|
|
|
|
|
|
|
// include the Node.js 'path' module at the top of your file
|
|
|
|
const path = require('path');
|
|
|
|
|
|
|
|
function handleSetTitle (event, title) {
|
|
|
|
const webContents = event.sender
|
|
|
|
const win = BrowserWindow.fromWebContents(webContents)
|
|
|
|
win.setTitle(title)
|
|
|
|
dialog.showOpenDialog({properties: ['openFile', 'openDirectory'] }).then(function (response) {
|
|
|
|
if (!response.canceled) {
|
|
|
|
// handle fully qualified file name
|
|
|
|
console.log(response.filePaths[0]);
|
|
|
|
} else {
|
|
|
|
console.log("no file selected");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-10-12 01:12:12 +00:00
|
|
|
function filenameToMimeType (filename) {
|
|
|
|
const extension = filename.split('.').pop();
|
|
|
|
switch (extension) {
|
|
|
|
case 'pdf':
|
|
|
|
return 'application/pdf';
|
|
|
|
case 'png':
|
|
|
|
return 'image/png';
|
|
|
|
case 'jpg':
|
|
|
|
case 'jpeg':
|
|
|
|
return 'image/jpeg';
|
2023-10-17 09:37:20 +00:00
|
|
|
case 'md':
|
2023-10-12 01:12:12 +00:00
|
|
|
case 'markdown':
|
|
|
|
return 'text/markdown';
|
|
|
|
case 'org':
|
|
|
|
return 'text/org';
|
|
|
|
default:
|
|
|
|
return 'text/plain';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-12 23:35:07 +00:00
|
|
|
function pushDataToKhoj (regenerate = false) {
|
2023-11-07 11:17:42 +00:00
|
|
|
// Don't sync if token or hostURL is not set or if already syncing
|
2023-11-09 01:59:02 +00:00
|
|
|
if (store.get('khojToken') === '' || store.get('hostURL') === '' || syncing === true) {
|
2023-11-07 11:17:42 +00:00
|
|
|
const win = BrowserWindow.getAllWindows()[0];
|
|
|
|
if (win) win.webContents.send('update-state', state);
|
|
|
|
return;
|
|
|
|
} else {
|
2023-11-09 01:59:02 +00:00
|
|
|
syncing = true;
|
2023-11-07 11:17:42 +00:00
|
|
|
}
|
|
|
|
|
2023-09-06 19:04:18 +00:00
|
|
|
let filesToPush = [];
|
2023-10-12 01:12:12 +00:00
|
|
|
const files = store.get('files') || [];
|
|
|
|
const folders = store.get('folders') || [];
|
|
|
|
state = { completed: true }
|
2023-09-06 19:04:18 +00:00
|
|
|
|
2023-10-18 08:00:41 +00:00
|
|
|
// Collect paths of all configured files to index
|
2023-10-12 01:12:12 +00:00
|
|
|
for (const file of files) {
|
|
|
|
filesToPush.push(file.path);
|
2023-09-06 19:04:18 +00:00
|
|
|
}
|
2023-10-12 01:12:12 +00:00
|
|
|
|
2023-10-18 08:00:41 +00:00
|
|
|
// Collect paths of all indexable files in configured folders
|
2023-10-12 01:12:12 +00:00
|
|
|
for (const folder of folders) {
|
|
|
|
const files = fs.readdirSync(folder.path, { withFileTypes: true });
|
|
|
|
for (const file of files) {
|
|
|
|
if (file.isFile() && validFileTypes.includes(file.name.split('.').pop())) {
|
|
|
|
filesToPush.push(path.join(folder.path, file.name));
|
2023-09-06 19:04:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const lastSync = store.get('lastSync') || [];
|
2023-10-12 01:12:12 +00:00
|
|
|
const formData = new FormData();
|
|
|
|
for (const file of filesToPush) {
|
2023-09-06 19:04:18 +00:00
|
|
|
const stats = fs.statSync(file);
|
2023-09-12 23:35:07 +00:00
|
|
|
if (!regenerate) {
|
2023-10-18 08:00:41 +00:00
|
|
|
// Only push files that have been modified since last sync
|
2023-09-12 23:35:07 +00:00
|
|
|
if (stats.mtime.toISOString() < lastSync.find((syncedFile) => syncedFile.path === file)?.datetime) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-09-06 19:04:18 +00:00
|
|
|
}
|
2023-09-12 23:35:07 +00:00
|
|
|
|
2023-10-18 08:00:41 +00:00
|
|
|
// Collect all updated or newly created files since last sync to index on Khoj server
|
2023-09-06 19:04:18 +00:00
|
|
|
try {
|
2023-10-17 20:05:50 +00:00
|
|
|
let encoding = binaryFileTypes.includes(file.split('.').pop()) ? "binary" : "utf8";
|
|
|
|
let mimeType = filenameToMimeType(file) + (encoding === "utf8" ? "; charset=UTF-8" : "");
|
|
|
|
let fileContent = Buffer.from(fs.readFileSync(file, { encoding: encoding }), encoding);
|
|
|
|
let fileObj = new Blob([fileContent], { type: mimeType });
|
2023-10-12 01:12:12 +00:00
|
|
|
formData.append('files', fileObj, file);
|
2023-09-06 19:04:18 +00:00
|
|
|
state[file] = {
|
|
|
|
success: true,
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
state[file] = {
|
|
|
|
success: false,
|
|
|
|
error: err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-18 08:00:41 +00:00
|
|
|
// Mark deleted files for removal from index on Khoj server
|
2023-09-06 19:04:18 +00:00
|
|
|
for (const syncedFile of lastSync) {
|
|
|
|
if (!filesToPush.includes(syncedFile.path)) {
|
2023-10-12 01:12:12 +00:00
|
|
|
fileObj = new Blob([""], { type: filenameToMimeType(syncedFile.path) });
|
|
|
|
formData.append('files', fileObj, syncedFile.path);
|
2023-09-06 19:04:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-18 08:00:41 +00:00
|
|
|
// Send collected files to Khoj server for indexing
|
2023-10-12 01:12:12 +00:00
|
|
|
if (!!formData?.entries()?.next().value) {
|
|
|
|
const hostURL = store.get('hostURL') || KHOJ_URL;
|
|
|
|
const headers = {
|
2023-10-26 19:33:03 +00:00
|
|
|
'Authorization': `Bearer ${store.get("khojToken")}`
|
2023-10-12 01:12:12 +00:00
|
|
|
};
|
2023-10-17 11:42:04 +00:00
|
|
|
axios.post(`${hostURL}/api/v1/index/update?force=${regenerate}&client=desktop`, formData, { headers })
|
2023-10-12 01:12:12 +00:00
|
|
|
.then(response => {
|
|
|
|
console.log(response.data);
|
|
|
|
let lastSync = [];
|
|
|
|
for (const file of filesToPush) {
|
|
|
|
lastSync.push({
|
|
|
|
path: file,
|
|
|
|
datetime: new Date().toISOString()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
store.set('lastSync', lastSync);
|
|
|
|
})
|
|
|
|
.catch(error => {
|
|
|
|
console.error(error);
|
2023-11-26 06:31:23 +00:00
|
|
|
if (error.response.status == 429) {
|
|
|
|
const win = BrowserWindow.getAllWindows()[0];
|
|
|
|
if (win) win.webContents.send('needsSubscription', true);
|
|
|
|
if (win) win.webContents.send('update-state', state);
|
|
|
|
}
|
2023-10-12 01:12:12 +00:00
|
|
|
state['completed'] = false
|
2023-10-18 08:00:41 +00:00
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
// Syncing complete
|
2023-11-09 01:59:02 +00:00
|
|
|
syncing = false;
|
2023-10-12 01:12:12 +00:00
|
|
|
const win = BrowserWindow.getAllWindows()[0];
|
2023-10-18 08:00:41 +00:00
|
|
|
if (win) win.webContents.send('update-state', state);
|
2023-10-12 01:12:12 +00:00
|
|
|
});
|
2023-10-18 08:00:41 +00:00
|
|
|
} else {
|
|
|
|
// Syncing complete
|
2023-11-09 01:59:02 +00:00
|
|
|
syncing = false;
|
2023-10-18 08:00:41 +00:00
|
|
|
const win = BrowserWindow.getAllWindows()[0];
|
|
|
|
if (win) win.webContents.send('update-state', state);
|
2023-10-12 01:12:12 +00:00
|
|
|
}
|
2023-09-06 19:04:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pushDataToKhoj();
|
|
|
|
|
2023-10-03 18:43:19 +00:00
|
|
|
async function handleFileOpen (type) {
|
|
|
|
let { canceled, filePaths } = {canceled: true, filePaths: []};
|
|
|
|
if (type === 'file') {
|
|
|
|
({ canceled, filePaths } = await dialog.showOpenDialog({properties: ['openFile' ], filters: [{ name: "Valid Khoj Files", extensions: validFileTypes}] }));
|
|
|
|
} else if (type === 'folder') {
|
|
|
|
({ canceled, filePaths } = await dialog.showOpenDialog({properties: ['openDirectory' ]}));
|
|
|
|
}
|
2023-09-06 19:04:18 +00:00
|
|
|
if (!canceled) {
|
|
|
|
const files = store.get('files') || [];
|
|
|
|
const folders = store.get('folders') || [];
|
|
|
|
|
|
|
|
for (const filePath of filePaths) {
|
|
|
|
console.log(filePath);
|
|
|
|
if (fs.existsSync(filePath)) {
|
|
|
|
const stats = fs.statSync(filePath);
|
|
|
|
if (stats.isFile()) {
|
|
|
|
console.log(`${filePath} is a file.`);
|
|
|
|
|
|
|
|
if (files.find((file) => file.path === filePath)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
files.push({path: filePath});
|
|
|
|
store.set('files', files);
|
|
|
|
} else if (stats.isDirectory()) {
|
|
|
|
console.log(`${filePath} is a directory.`);
|
|
|
|
|
|
|
|
if (folders.find((folder) => folder.path === filePath)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
folders.push({path: filePath});
|
|
|
|
store.set('folders', folders);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
console.log(`${filePath} does not exist.`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
files: store.get('files'),
|
|
|
|
folders: store.get('folders')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-26 19:33:03 +00:00
|
|
|
async function getToken () {
|
|
|
|
return store.get('khojToken');
|
|
|
|
}
|
|
|
|
|
|
|
|
async function setToken (event, token) {
|
|
|
|
store.set('khojToken', token);
|
|
|
|
return store.get('khojToken');
|
|
|
|
}
|
|
|
|
|
2023-09-06 19:04:18 +00:00
|
|
|
async function getFiles () {
|
|
|
|
return store.get('files');
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getFolders () {
|
|
|
|
return store.get('folders');
|
|
|
|
}
|
|
|
|
|
|
|
|
async function setURL (event, url) {
|
2023-11-01 00:59:53 +00:00
|
|
|
// Sanitize the URL. Remove trailing slash if present. Add http:// if not present.
|
|
|
|
url = url.replace(/\/$/, "");
|
|
|
|
if (!url.match(/^[a-zA-Z]+:\/\//)) {
|
|
|
|
url = `http://${url}`;
|
|
|
|
}
|
|
|
|
|
2023-09-06 19:04:18 +00:00
|
|
|
store.set('hostURL', url);
|
|
|
|
return store.get('hostURL');
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getURL () {
|
|
|
|
return store.get('hostURL');
|
|
|
|
}
|
|
|
|
|
|
|
|
async function removeFile (event, filePath) {
|
|
|
|
const files = store.get('files');
|
|
|
|
const newFiles = files.filter((file) => file.path !== filePath);
|
|
|
|
store.set('files', newFiles);
|
|
|
|
return newFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function removeFolder (event, folderPath) {
|
|
|
|
const folders = store.get('folders');
|
|
|
|
const newFolders = folders.filter((folder) => folder.path !== folderPath);
|
|
|
|
store.set('folders', newFolders);
|
|
|
|
return newFolders;
|
|
|
|
}
|
|
|
|
|
2023-09-12 23:35:07 +00:00
|
|
|
async function syncData (regenerate = false) {
|
2023-09-06 19:04:18 +00:00
|
|
|
try {
|
2023-09-12 23:35:07 +00:00
|
|
|
pushDataToKhoj(regenerate);
|
2023-09-06 19:04:18 +00:00
|
|
|
const date = new Date();
|
|
|
|
console.log('Pushing data to Khoj at: ', date);
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-07 11:37:16 +00:00
|
|
|
async function deleteAllFiles () {
|
|
|
|
try {
|
|
|
|
store.set('files', []);
|
|
|
|
store.set('folders', []);
|
|
|
|
pushDataToKhoj(true);
|
|
|
|
const date = new Date();
|
|
|
|
console.log('Pushing data to Khoj at: ', date);
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-03 09:46:39 +00:00
|
|
|
let firstRun = true;
|
2023-10-26 19:33:03 +00:00
|
|
|
let win = null;
|
2023-11-03 03:40:35 +00:00
|
|
|
const createWindow = (tab = 'chat.html') => {
|
2023-10-26 19:33:03 +00:00
|
|
|
win = new BrowserWindow({
|
2023-09-06 19:04:18 +00:00
|
|
|
width: 800,
|
|
|
|
height: 800,
|
2023-11-03 09:46:39 +00:00
|
|
|
show: false,
|
2023-09-06 19:04:18 +00:00
|
|
|
// titleBarStyle: 'hidden',
|
|
|
|
webPreferences: {
|
|
|
|
preload: path.join(__dirname, 'preload.js'),
|
|
|
|
nodeIntegration: true,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const job = new cron('0 */10 * * * *', function() {
|
|
|
|
try {
|
|
|
|
pushDataToKhoj();
|
|
|
|
const date = new Date();
|
|
|
|
console.log('Pushing data to Khoj at: ', date);
|
|
|
|
win.webContents.send('update-state', state);
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
win.setResizable(true);
|
|
|
|
win.setOpacity(0.95);
|
2023-11-03 09:46:39 +00:00
|
|
|
win.setBackgroundColor('#f5f4f3');
|
2023-09-06 19:04:18 +00:00
|
|
|
win.setHasShadow(true);
|
|
|
|
|
|
|
|
job.start();
|
|
|
|
|
2023-10-26 19:33:03 +00:00
|
|
|
win.loadFile(tab)
|
2023-11-03 09:46:39 +00:00
|
|
|
|
|
|
|
if (firstRun === true) {
|
|
|
|
firstRun = false;
|
|
|
|
|
|
|
|
// Create splash screen
|
2023-11-04 05:20:11 +00:00
|
|
|
var splash = new BrowserWindow({width: 400, height: 400, transparent: true, frame: false, alwaysOnTop: true});
|
|
|
|
splash.setOpacity(1.0);
|
2023-11-03 09:46:39 +00:00
|
|
|
splash.setBackgroundColor('#d16b4e');
|
|
|
|
splash.loadFile('splash.html');
|
|
|
|
|
|
|
|
// Show splash screen on app load
|
|
|
|
win.once('ready-to-show', () => {
|
|
|
|
setTimeout(function(){ splash.close(); win.show(); }, 4500);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// Show main window directly if not first run
|
|
|
|
win.once('ready-to-show', () => { win.show(); });
|
|
|
|
}
|
2023-09-06 19:04:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
app.whenReady().then(() => {
|
|
|
|
ipcMain.on('set-title', handleSetTitle);
|
|
|
|
|
2023-10-03 18:43:19 +00:00
|
|
|
ipcMain.handle('handleFileOpen', (event, type) => {
|
|
|
|
return handleFileOpen(type);
|
|
|
|
});
|
2023-09-06 19:04:18 +00:00
|
|
|
|
|
|
|
ipcMain.on('update-state', (event, arg) => {
|
|
|
|
console.log(arg);
|
|
|
|
event.reply('update-state', arg);
|
|
|
|
});
|
|
|
|
|
2023-11-26 06:31:23 +00:00
|
|
|
ipcMain.on('needsSubscription', (event, arg) => {
|
|
|
|
console.log(arg);
|
|
|
|
event.reply('needsSubscription', arg);
|
|
|
|
});
|
|
|
|
|
2023-11-16 06:33:50 +00:00
|
|
|
ipcMain.on('navigate', (event, page) => {
|
|
|
|
win.loadFile(page);
|
|
|
|
});
|
|
|
|
|
|
|
|
ipcMain.on('navigateToWebApp', (event, page) => {
|
|
|
|
shell.openExternal(`${store.get('hostURL')}/${page}`);
|
|
|
|
});
|
|
|
|
|
2023-09-06 19:04:18 +00:00
|
|
|
ipcMain.handle('getFiles', getFiles);
|
|
|
|
ipcMain.handle('getFolders', getFolders);
|
|
|
|
|
|
|
|
ipcMain.handle('removeFile', removeFile);
|
|
|
|
ipcMain.handle('removeFolder', removeFolder);
|
|
|
|
|
|
|
|
ipcMain.handle('setURL', setURL);
|
|
|
|
ipcMain.handle('getURL', getURL);
|
|
|
|
|
2023-10-26 19:33:03 +00:00
|
|
|
ipcMain.handle('setToken', setToken);
|
|
|
|
ipcMain.handle('getToken', getToken);
|
|
|
|
|
2023-09-12 23:35:07 +00:00
|
|
|
ipcMain.handle('syncData', (event, regenerate) => {
|
|
|
|
syncData(regenerate);
|
|
|
|
});
|
2023-11-07 11:37:16 +00:00
|
|
|
ipcMain.handle('deleteAllFiles', deleteAllFiles);
|
2023-09-06 19:04:18 +00:00
|
|
|
|
|
|
|
createWindow()
|
|
|
|
|
|
|
|
app.setAboutPanelOptions({
|
|
|
|
applicationName: "Khoj",
|
2023-11-04 03:56:27 +00:00
|
|
|
applicationVersion: khojPackage.version,
|
|
|
|
version: khojPackage.version,
|
|
|
|
authors: "Saba Imran, Debanjum Singh Solanky and contributors",
|
2023-09-06 19:04:18 +00:00
|
|
|
website: "https://khoj.dev",
|
2023-11-04 03:56:27 +00:00
|
|
|
copyright: "GPL v3",
|
|
|
|
iconPath: path.join(__dirname, 'assets', 'icons', 'favicon-128x128.png')
|
2023-09-06 19:04:18 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
app.on('ready', async() => {
|
|
|
|
try {
|
|
|
|
const result = await todesktop.autoUpdater.checkForUpdates();
|
|
|
|
if (result.updateInfo) {
|
|
|
|
console.log("Update found:", result.updateInfo.version);
|
|
|
|
todesktop.autoUpdater.restartAndInstall();
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.log("Update check failed:", e);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
app.on('activate', () => {
|
|
|
|
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
app.on('window-all-closed', () => {
|
|
|
|
if (process.platform !== 'darwin') app.quit()
|
|
|
|
})
|
2023-10-26 19:33:03 +00:00
|
|
|
|
2023-11-04 03:56:27 +00:00
|
|
|
/*
|
|
|
|
** About Page
|
|
|
|
*/
|
|
|
|
|
|
|
|
let aboutWindow;
|
|
|
|
|
|
|
|
function openAboutWindow() {
|
|
|
|
if (aboutWindow) { aboutWindow.focus(); return; }
|
|
|
|
|
|
|
|
aboutWindow = new BrowserWindow({
|
|
|
|
width: 400,
|
|
|
|
height: 400,
|
|
|
|
titleBarStyle: 'hidden',
|
|
|
|
show: false,
|
|
|
|
webPreferences: {
|
|
|
|
preload: path.join(__dirname, 'preload.js'),
|
|
|
|
nodeIntegration: true,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
aboutWindow.loadFile('about.html');
|
|
|
|
|
|
|
|
// Pass OS, Khoj version to About page
|
|
|
|
aboutWindow.webContents.on('did-finish-load', () => {
|
|
|
|
aboutWindow.webContents.send('appInfo', { version: khojPackage.version, platform: process.platform });
|
|
|
|
});
|
|
|
|
|
|
|
|
// Open links in external browser
|
|
|
|
aboutWindow.webContents.setWindowOpenHandler(({ url }) => {
|
|
|
|
shell.openExternal(url);
|
|
|
|
return { action: 'deny' };
|
|
|
|
});
|
|
|
|
|
|
|
|
aboutWindow.once('ready-to-show', () => { aboutWindow.show(); });
|
|
|
|
aboutWindow.on('closed', () => { aboutWindow = null; });
|
|
|
|
}
|
|
|
|
|
2023-10-26 19:33:03 +00:00
|
|
|
/*
|
|
|
|
** System Tray Icon
|
|
|
|
*/
|
|
|
|
|
|
|
|
let tray
|
|
|
|
|
|
|
|
openWindow = (page) => {
|
|
|
|
if (BrowserWindow.getAllWindows().length === 0) {
|
|
|
|
createWindow(page);
|
|
|
|
} else {
|
|
|
|
win.loadFile(page); win.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
app.whenReady().then(() => {
|
|
|
|
const icon = nativeImage.createFromPath('assets/icons/favicon-20x20.png')
|
|
|
|
tray = new Tray(icon)
|
|
|
|
|
|
|
|
const contextMenu = Menu.buildFromTemplate([
|
|
|
|
{ label: 'Chat', type: 'normal', click: () => { openWindow('chat.html'); }},
|
2023-11-03 03:40:35 +00:00
|
|
|
{ label: 'Search', type: 'normal', click: () => { openWindow('search.html') }},
|
2023-10-26 19:33:03 +00:00
|
|
|
{ label: 'Configure', type: 'normal', click: () => { openWindow('config.html') }},
|
|
|
|
{ type: 'separator' },
|
2023-11-04 03:56:27 +00:00
|
|
|
{ label: 'About Khoj', type: 'normal', click: () => { openAboutWindow(); } },
|
2023-10-26 19:33:03 +00:00
|
|
|
{ label: 'Quit', type: 'normal', click: () => { app.quit() } }
|
|
|
|
])
|
|
|
|
|
|
|
|
tray.setToolTip('Khoj')
|
|
|
|
tray.setContextMenu(contextMenu)
|
|
|
|
})
|