* hackathon: Refactor Jan into an Electron app * chore: correct NextJS export output path * chore: build electron app for all production targets * fix: correct assetPrefix for production build * chore: preferences shortcut * chore: refactor * chore: refactor into ts * feature/#52-compile-plugin-with-webpack * chore: introduce renderer <=> plugins <=> main invocation * chore: suppress errors - deprecate graphql & next-auth * chore: data plugin functions * add llm support Signed-off-by: James <james@jan.ai> * chore: update plugin * chore: introduce data-plugin * chore: plugin invokes main with args and synchronously * chore: install db plugin should setup db * feature: Data Driver Plugin - Load conversations and messages from data plugin * chore: store text message sent * chore: shared core services * feature: inference service * chore: conversations ordering * adding model management service Signed-off-by: James <james@jan.ai> * chore: strict type * feature: abstract plugin preferences * chore: abstract plugin preference * Revert "chore: strict type" This reverts commit 9be188d827a0b2e081e9e04b192c323799de5bb5. * chore: base-plugin styling * feature: create and delete conversation * chore: fix plugin search & clean messages * chore: typing indicator * chore: refactor useSendChatMessage * chore: persists inserted id to in-memory messages * chore: search conversation history * add delete and download model (#189) Signed-off-by: James <james@jan.ai> Co-authored-by: James <james@jan.ai> * chore: add empty state for conversation list * chore: prompt missing extension function & fix app crashes * chore: prompt user to install required plugins * chore: add launch background * chore: relaunch app on model downloaded * Jan app add installation instruction (#191) Co-authored-by: Hien To <> * Chore: rename folder web-client to app (#192) * Chore: rename folder web-client to app --------- Co-authored-by: Hien To <> * revert: add pre-install package * add progress for downloading model Signed-off-by: James <james@jan.ai> * feature: production bundle * add download progress Signed-off-by: James <james@jan.ai> * chore: add new chat function * fix: electron asar unpack modules & dynamic import * chore: fix unpack * chore: fix dev pack * Add instruction to build dmg file to README.md * init model dynamically Signed-off-by: James <james@jan.ai> --------- Signed-off-by: James <james@jan.ai> Co-authored-by: James <james@jan.ai> Co-authored-by: NamH <NamNh0122@gmail.com> Co-authored-by: hiento09 <136591877+hiento09@users.noreply.github.com> Co-authored-by: Hien To <>
92 lines
2.8 KiB
JavaScript
92 lines
2.8 KiB
JavaScript
import { ipcMain, webContents } from "electron"
|
|
|
|
import { getPlugin, getActivePlugins, installPlugins, removePlugin, getAllPlugins } from "./store"
|
|
import { pluginsPath, confirmInstall } from './globals'
|
|
|
|
// Throw an error if pluginsPath has not yet been provided by usePlugins.
|
|
const checkPluginsPath = () => {
|
|
if (!pluginsPath) throw Error('Path to plugins folder has not yet been set up.')
|
|
}
|
|
let active = false
|
|
/**
|
|
* Provide the renderer process access to the plugins.
|
|
**/
|
|
export default function () {
|
|
if (active) return
|
|
// Register IPC route to install a plugin
|
|
ipcMain.handle('pluggable:install', async (e, plugins) => {
|
|
checkPluginsPath()
|
|
|
|
// Validate install request from backend for security.
|
|
const specs = plugins.map(plg => typeof plg === 'object' ? plg.specifier : plg)
|
|
const conf = await confirmInstall(specs)
|
|
if (!conf) return { cancelled: true }
|
|
|
|
// Install and activate all provided plugins
|
|
const installed = await installPlugins(plugins)
|
|
return JSON.parse(JSON.stringify(installed))
|
|
})
|
|
|
|
// Register IPC route to uninstall a plugin
|
|
ipcMain.handle('pluggable:uninstall', async (e, plugins, reload) => {
|
|
checkPluginsPath()
|
|
|
|
// Uninstall all provided plugins
|
|
for (const plg of plugins) {
|
|
const plugin = getPlugin(plg)
|
|
await plugin.uninstall()
|
|
removePlugin(plugin.name)
|
|
}
|
|
|
|
// Reload all renderer pages if needed
|
|
reload && webContents.getAllWebContents().forEach(wc => wc.reload())
|
|
return true
|
|
})
|
|
|
|
// Register IPC route to update a plugin
|
|
ipcMain.handle('pluggable:update', (e, plugins, reload) => {
|
|
checkPluginsPath()
|
|
|
|
// Update all provided plugins
|
|
let updated = []
|
|
for (const plg of plugins) {
|
|
const plugin = getPlugin(plg)
|
|
const res = plugin.update()
|
|
if (res) updated.push(plugin)
|
|
}
|
|
|
|
// Reload all renderer pages if needed
|
|
if (updated.length && reload) webContents.getAllWebContents().forEach(wc => wc.reload())
|
|
|
|
return JSON.parse(JSON.stringify(updated))
|
|
})
|
|
|
|
// Register IPC route to check if updates are available for a plugin
|
|
ipcMain.handle('pluggable:updatesAvailable', (e, names) => {
|
|
checkPluginsPath()
|
|
|
|
const plugins = names ? names.map(name => getPlugin(name)) : getAllPlugins()
|
|
|
|
const updates = {}
|
|
for (const plugin of plugins) {
|
|
updates[plugin.name] = plugin.isUpdateAvailable()
|
|
}
|
|
return updates
|
|
})
|
|
|
|
// Register IPC route to get the list of active plugins
|
|
ipcMain.handle('pluggable:getActivePlugins', () => {
|
|
checkPluginsPath()
|
|
return JSON.parse(JSON.stringify(getActivePlugins()))
|
|
})
|
|
|
|
// Register IPC route to toggle the active state of a plugin
|
|
ipcMain.handle('pluggable:togglePluginActive', (e, plg, active) => {
|
|
checkPluginsPath()
|
|
const plugin = getPlugin(plg)
|
|
return JSON.parse(JSON.stringify(plugin.setActive(active)))
|
|
})
|
|
|
|
active = true
|
|
}
|