Merge branch 'main' into feat_adr_002
This commit is contained in:
commit
6fc7373fe9
158
.github/workflows/build-app.yml
vendored
Normal file
158
.github/workflows/build-app.yml
vendored
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
name: Jan Build MacOS App
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ['v*.*.*']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-macos:
|
||||||
|
runs-on: macos-latest
|
||||||
|
environment: production
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Getting the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Installing node
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install jq
|
||||||
|
uses: dcarbone/install-jq-action@v2.0.1
|
||||||
|
|
||||||
|
- name: Get tag
|
||||||
|
id: tag
|
||||||
|
uses: dawidd6/action-get-tag@v1
|
||||||
|
|
||||||
|
- name: Update app version base on tag
|
||||||
|
run: |
|
||||||
|
if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "Error: Tag is not valid!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
|
||||||
|
mv /tmp/package.json electron/package.json
|
||||||
|
env:
|
||||||
|
VERSION_TAG: ${{ steps.tag.outputs.tag }}
|
||||||
|
|
||||||
|
- name: Get Cer for code signing
|
||||||
|
run: base64 -d <<< "$CODE_SIGN_P12_BASE64" > /tmp/codesign.p12
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CODE_SIGN_P12_BASE64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
|
||||||
|
|
||||||
|
- uses: apple-actions/import-codesign-certs@v2
|
||||||
|
with:
|
||||||
|
p12-file-base64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
|
||||||
|
p12-password: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Install yarn dependencies
|
||||||
|
run: |
|
||||||
|
yarn install
|
||||||
|
yarn build:plugins-darwin
|
||||||
|
|
||||||
|
- name: Build and publish app
|
||||||
|
run: |
|
||||||
|
yarn build:publish-darwin
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
CSC_LINK: "/tmp/codesign.p12"
|
||||||
|
CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
|
||||||
|
CSC_IDENTITY_AUTO_DISCOVERY: "true"
|
||||||
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||||
|
|
||||||
|
build-windows-x64:
|
||||||
|
runs-on: windows-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Getting the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Installing node
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install jq
|
||||||
|
uses: dcarbone/install-jq-action@v2.0.1
|
||||||
|
|
||||||
|
- name: Get tag
|
||||||
|
id: tag
|
||||||
|
uses: dawidd6/action-get-tag@v1
|
||||||
|
|
||||||
|
- name: Update app version base on tag
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "Error: Tag is not valid!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
|
||||||
|
mv /tmp/package.json electron/package.json
|
||||||
|
env:
|
||||||
|
VERSION_TAG: ${{ steps.tag.outputs.tag }}
|
||||||
|
|
||||||
|
- name: Install yarn dependencies
|
||||||
|
run: |
|
||||||
|
yarn config set network-timeout 300000
|
||||||
|
yarn install
|
||||||
|
yarn build:plugins
|
||||||
|
|
||||||
|
- name: Build and publish app
|
||||||
|
run: |
|
||||||
|
yarn build:publish-win32
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
build-linux-x64:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: production
|
||||||
|
env:
|
||||||
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Getting the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Installing node
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install jq
|
||||||
|
uses: dcarbone/install-jq-action@v2.0.1
|
||||||
|
|
||||||
|
- name: Install Snapcraft
|
||||||
|
uses: samuelmeuli/action-snapcraft@v2
|
||||||
|
|
||||||
|
- name: Get tag
|
||||||
|
id: tag
|
||||||
|
uses: dawidd6/action-get-tag@v1
|
||||||
|
|
||||||
|
- name: Update app version base on tag
|
||||||
|
run: |
|
||||||
|
if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "Error: Tag is not valid!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
|
||||||
|
mv /tmp/package.json electron/package.json
|
||||||
|
env:
|
||||||
|
VERSION_TAG: ${{ steps.tag.outputs.tag }}
|
||||||
|
|
||||||
|
- name: Install yarn dependencies
|
||||||
|
run: |
|
||||||
|
yarn config set network-timeout 300000
|
||||||
|
yarn install
|
||||||
|
yarn build:plugins
|
||||||
|
|
||||||
|
- name: Build and publish app
|
||||||
|
run: |
|
||||||
|
yarn build:publish-linux
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
88
.github/workflows/linter-and-test.yml
vendored
Normal file
88
.github/workflows/linter-and-test.yml
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
name: Linter & Test
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'electron/**'
|
||||||
|
- .github/workflows/linter-and-test.yml
|
||||||
|
- 'web/**'
|
||||||
|
- 'package.json'
|
||||||
|
- 'node_modules/**'
|
||||||
|
- 'yarn.lock'
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'electron/**'
|
||||||
|
- .github/workflows/linter-and-test.yml
|
||||||
|
- 'web/**'
|
||||||
|
- 'package.json'
|
||||||
|
- 'node_modules/**'
|
||||||
|
- 'yarn.lock'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-on-macos:
|
||||||
|
runs-on: [self-hosted, macOS, macos-desktop]
|
||||||
|
steps:
|
||||||
|
- name: Getting the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Installing node
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Linter and test
|
||||||
|
run: |
|
||||||
|
yarn config set network-timeout 300000
|
||||||
|
yarn install
|
||||||
|
yarn lint
|
||||||
|
yarn build:plugins
|
||||||
|
yarn build
|
||||||
|
yarn test
|
||||||
|
env:
|
||||||
|
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
||||||
|
|
||||||
|
test-on-windows:
|
||||||
|
runs-on: [self-hosted, Windows, windows-desktop]
|
||||||
|
steps:
|
||||||
|
- name: Getting the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Installing node
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Linter and test
|
||||||
|
run: |
|
||||||
|
yarn config set network-timeout 300000
|
||||||
|
yarn install
|
||||||
|
yarn lint
|
||||||
|
yarn build:plugins
|
||||||
|
yarn build:win32
|
||||||
|
yarn test
|
||||||
|
|
||||||
|
test-on-ubuntu:
|
||||||
|
runs-on: [self-hosted, Linux, ubuntu-desktop]
|
||||||
|
steps:
|
||||||
|
- name: Getting the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Installing node
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Linter and test
|
||||||
|
run: |
|
||||||
|
yarn config set network-timeout 300000
|
||||||
|
yarn install
|
||||||
|
yarn lint
|
||||||
|
yarn build:plugins
|
||||||
|
yarn build:linux
|
||||||
|
yarn test
|
||||||
|
env:
|
||||||
|
DISPLAY: ":0"
|
||||||
50
.github/workflows/macos-build-app.yml
vendored
50
.github/workflows/macos-build-app.yml
vendored
@ -1,50 +0,0 @@
|
|||||||
name: Jan Build MacOS App
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags: ['v*.*.*']
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-macos-app:
|
|
||||||
runs-on: macos-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- name: Getting the repo
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Installing node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
|
|
||||||
- name: Install jq
|
|
||||||
uses: dcarbone/install-jq-action@v2.0.1
|
|
||||||
|
|
||||||
- name: Get tag
|
|
||||||
id: tag
|
|
||||||
uses: dawidd6/action-get-tag@v1
|
|
||||||
|
|
||||||
- name: Update app version base on tag
|
|
||||||
run: |
|
|
||||||
if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
||||||
echo "Error: Tag is not valid!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
|
|
||||||
mv /tmp/package.json electron/package.json
|
|
||||||
env:
|
|
||||||
VERSION_TAG: ${{ steps.tag.outputs.tag }}
|
|
||||||
|
|
||||||
- name: Install yarn dependencies
|
|
||||||
run: |
|
|
||||||
yarn install
|
|
||||||
yarn build:plugins
|
|
||||||
|
|
||||||
- name: Build and publish app
|
|
||||||
run: |
|
|
||||||
yarn build:publish
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,7 +5,6 @@
|
|||||||
models/**
|
models/**
|
||||||
error.log
|
error.log
|
||||||
node_modules
|
node_modules
|
||||||
package-lock.json
|
|
||||||
*.tgz
|
*.tgz
|
||||||
yarn.lock
|
yarn.lock
|
||||||
dist
|
dist
|
||||||
|
|||||||
29
adr/adr-003-jan-plugins.md
Normal file
29
adr/adr-003-jan-plugins.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# ADR 003: JAN PLUGINS
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
- Oct 5th 2023: Initial draft
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Modular Architecture w/ Plugins:
|
||||||
|
|
||||||
|
- Jan will have an architecture similar to VSCode or k8Lens
|
||||||
|
- "Desktop Application" whose functionality can be extended thru plugins
|
||||||
|
- Jan's architecture will need to accomodate plugins for (a) Persistence(b) IAM(c) Teams and RBAC(d) Policy engines(e) "Apps" (i.e. higher-order business logic)(f) Themes (UI)
|
||||||
|
- Nitro's architecture will need to accomodate plugins for different "model backends"(a) llama.cpp(b) rkwk (and others)(c) 3rd-party AIs
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
What becomes easier or more difficult to do because of this change?
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
[Plugin APIs](./adr-003-jan-plugins.md)
|
||||||
37
adr/docs/adr-003-plugins.md
Normal file
37
adr/docs/adr-003-plugins.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
## JAN service & plugin APIs
|
||||||
|
|
||||||
|
Jan frontend components will communicate with plugin functions via Service Interfaces:
|
||||||
|
|
||||||
|
|
||||||
|
All of the available APIs are listed in [CoreService](../../web/shared/coreService.ts)
|
||||||
|
|
||||||
|
- Data Service:
|
||||||
|
- GET_CONVERSATIONS: retrieve all of the conversations
|
||||||
|
- CREATE_CONVERSATION: start a new conversation
|
||||||
|
- DELETE_CONVERSATION: delete an existing conversation
|
||||||
|
- GET_CONVERSATION_MESSAGES: retrieve a certain conversation messages
|
||||||
|
- CREATE_MESSAGE: store a new message (both sent & received)
|
||||||
|
- UPDATE_MESSAGE: update an existing message (streaming)
|
||||||
|
- STORE_MODEL: store new model information (when clicking download)
|
||||||
|
- UPDATE_FINISHED_DOWNLOAD: mark a model as downloaded
|
||||||
|
- GET_UNFINISHED_DOWNLOAD_MODELS: retrieve all unfinished downloading model (TBD)
|
||||||
|
- GET_FINISHED_DOWNLOAD_MODELS: retrieve all finished downloading model (TBD)
|
||||||
|
- DELETE_DOWNLOAD_MODEL: delete a model (TBD)
|
||||||
|
- GET_MODEL_BY_ID: retrieve model information by its ID
|
||||||
|
|
||||||
|
- Inference Service:
|
||||||
|
- INFERENCE_URL: retrieve inference endpoint served by plugin
|
||||||
|
- INIT_MODEL: runs a model
|
||||||
|
- STOP_MODEL: stop a running model
|
||||||
|
|
||||||
|
- Model Management Service: (TBD)
|
||||||
|
- GET_AVAILABLE_MODELS: retrieve available models (deprecate soon)
|
||||||
|
- GET_DOWNLOADED_MODELS: (deprecated)
|
||||||
|
- DELETE_MODEL: (deprecated)
|
||||||
|
- DOWNLOAD_MODEL: start to download a model
|
||||||
|
- SEARCH_MODELS: explore models with search query on HuggingFace (TBD)
|
||||||
|
|
||||||
|
- Monitoring service:
|
||||||
|
- GET_RESOURCES_INFORMATION: retrieve total & used memory information
|
||||||
|
- GET_CURRENT_LOAD_INFORMATION: retrieve CPU load information
|
||||||
|
|
||||||
BIN
adr/images/adr-003-01.png
Normal file
BIN
adr/images/adr-003-01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 335 KiB |
@ -34,5 +34,11 @@ module.exports = {
|
|||||||
{ name: "Link", linkAttribute: "to" },
|
{ name: "Link", linkAttribute: "to" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
ignorePatterns: ["renderer/*", "node_modules/*", "core/plugins"],
|
ignorePatterns: [
|
||||||
|
"build",
|
||||||
|
"renderer",
|
||||||
|
"node_modules",
|
||||||
|
"core/plugins",
|
||||||
|
"core/**/*.test.js",
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
5
electron/auto-sign.sh
Executable file
5
electron/auto-sign.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DEVELOPER_ID="Developer ID Application: Eigenvector Pte Ltd"
|
||||||
|
|
||||||
|
find electron -type f -perm +111 -exec codesign -s "Developer ID Application: Eigenvector Pte Ltd (YT49P7GXG4)" --options=runtime {} \;
|
||||||
@ -16,11 +16,23 @@ class Plugin {
|
|||||||
/** @type {boolean} Whether this plugin should be activated when its activation points are triggered. */
|
/** @type {boolean} Whether this plugin should be activated when its activation points are triggered. */
|
||||||
active
|
active
|
||||||
|
|
||||||
constructor(name, url, activationPoints, active) {
|
/** @type {string} Plugin's description. */
|
||||||
|
description
|
||||||
|
|
||||||
|
/** @type {string} Plugin's version. */
|
||||||
|
version
|
||||||
|
|
||||||
|
/** @type {string} Plugin's logo. */
|
||||||
|
icon
|
||||||
|
|
||||||
|
constructor(name, url, activationPoints, active, description, version, icon) {
|
||||||
this.name = name
|
this.name = name
|
||||||
this.url = url
|
this.url = url
|
||||||
this.activationPoints = activationPoints
|
this.activationPoints = activationPoints
|
||||||
this.active = active
|
this.active = active
|
||||||
|
this.description = description
|
||||||
|
this.version = version
|
||||||
|
this.icon = icon
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export async function install(plugins) {
|
|||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const plgList = await window.pluggableElectronIpc.install(plugins);
|
const plgList = await window.pluggableElectronIpc.install(plugins);
|
||||||
if (plgList.cancelled) return false;
|
if (plgList.cancelled) return false;
|
||||||
return plgList.map((plg) => {
|
return plgList.map((plg) => {
|
||||||
@ -50,6 +51,7 @@ export function uninstall(plugins, reload = true) {
|
|||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
return window.pluggableElectronIpc.uninstall(plugins, reload);
|
return window.pluggableElectronIpc.uninstall(plugins, reload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +64,7 @@ export async function getActive() {
|
|||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const plgList = await window.pluggableElectronIpc.getActive();
|
const plgList = await window.pluggableElectronIpc.getActive();
|
||||||
return plgList.map(
|
return plgList.map(
|
||||||
(plugin) =>
|
(plugin) =>
|
||||||
@ -69,7 +72,10 @@ export async function getActive() {
|
|||||||
plugin.name,
|
plugin.name,
|
||||||
plugin.url,
|
plugin.url,
|
||||||
plugin.activationPoints,
|
plugin.activationPoints,
|
||||||
plugin.active
|
plugin.active,
|
||||||
|
plugin.description,
|
||||||
|
plugin.version,
|
||||||
|
plugin.icon
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -83,6 +89,7 @@ export async function registerActive() {
|
|||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const plgList = await window.pluggableElectronIpc.getActive();
|
const plgList = await window.pluggableElectronIpc.getActive();
|
||||||
plgList.forEach((plugin) =>
|
plgList.forEach((plugin) =>
|
||||||
register(
|
register(
|
||||||
@ -107,6 +114,7 @@ export async function update(plugins, reload = true) {
|
|||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const plgList = await window.pluggableElectronIpc.update(plugins, reload);
|
const plgList = await window.pluggableElectronIpc.update(plugins, reload);
|
||||||
return plgList.map(
|
return plgList.map(
|
||||||
(plugin) =>
|
(plugin) =>
|
||||||
@ -129,6 +137,7 @@ export function updatesAvailable(plugin) {
|
|||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
return window.pluggableElectronIpc.updatesAvailable(plugin);
|
return window.pluggableElectronIpc.updatesAvailable(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +152,7 @@ export async function toggleActive(plugin, active) {
|
|||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const plg = await window.pluggableElectronIpc.toggleActive(plugin, active);
|
const plg = await window.pluggableElectronIpc.toggleActive(plugin, active);
|
||||||
return new Plugin(plg.name, plg.url, plg.activationPoints, plg.active);
|
return new Plugin(plg.name, plg.url, plg.activationPoints, plg.active);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ export * as activationPoints from "./activation-manager.js";
|
|||||||
export * as plugins from "./facade.js";
|
export * as plugins from "./facade.js";
|
||||||
export { default as ExtensionPoint } from "./ExtensionPoint.js";
|
export { default as ExtensionPoint } from "./ExtensionPoint.js";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
if (typeof window !== "undefined" && !window.pluggableElectronIpc)
|
if (typeof window !== "undefined" && !window.pluggableElectronIpc)
|
||||||
console.warn(
|
console.warn(
|
||||||
"Facade is not registered in preload. Facade functions will throw an error if used."
|
"Facade is not registered in preload. Facade functions will throw an error if used."
|
||||||
|
|||||||
@ -1,30 +1,32 @@
|
|||||||
import { ipcRenderer, contextBridge } from "electron"
|
const { ipcRenderer, contextBridge } = require("electron");
|
||||||
|
|
||||||
export default function useFacade() {
|
function useFacade() {
|
||||||
const interfaces = {
|
const interfaces = {
|
||||||
install(plugins) {
|
install(plugins) {
|
||||||
return ipcRenderer.invoke('pluggable:install', plugins)
|
return ipcRenderer.invoke("pluggable:install", plugins);
|
||||||
},
|
},
|
||||||
uninstall(plugins, reload) {
|
uninstall(plugins, reload) {
|
||||||
return ipcRenderer.invoke('pluggable:uninstall', plugins, reload)
|
return ipcRenderer.invoke("pluggable:uninstall", plugins, reload);
|
||||||
},
|
},
|
||||||
getActive() {
|
getActive() {
|
||||||
return ipcRenderer.invoke('pluggable:getActivePlugins')
|
return ipcRenderer.invoke("pluggable:getActivePlugins");
|
||||||
},
|
},
|
||||||
update(plugins, reload) {
|
update(plugins, reload) {
|
||||||
return ipcRenderer.invoke('pluggable:update', plugins, reload)
|
return ipcRenderer.invoke("pluggable:update", plugins, reload);
|
||||||
},
|
},
|
||||||
updatesAvailable(plugin) {
|
updatesAvailable(plugin) {
|
||||||
return ipcRenderer.invoke('pluggable:updatesAvailable', plugin)
|
return ipcRenderer.invoke("pluggable:updatesAvailable", plugin);
|
||||||
},
|
},
|
||||||
toggleActive(plugin, active) {
|
toggleActive(plugin, active) {
|
||||||
return ipcRenderer.invoke('pluggable:togglePluginActive', plugin, active)
|
return ipcRenderer.invoke("pluggable:togglePluginActive", plugin, active);
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
if (contextBridge) {
|
if (contextBridge) {
|
||||||
contextBridge.exposeInMainWorld('pluggableElectronIpc', interfaces)
|
contextBridge.exposeInMainWorld("pluggableElectronIpc", interfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
return interfaces
|
return interfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = useFacade;
|
||||||
|
|||||||
@ -18,6 +18,8 @@ class Plugin {
|
|||||||
* @property {string} version Version of the package as defined in the manifest.
|
* @property {string} version Version of the package as defined in the manifest.
|
||||||
* @property {Array<string>} activationPoints List of {@link ./Execution-API#activationPoints|activation points}.
|
* @property {Array<string>} activationPoints List of {@link ./Execution-API#activationPoints|activation points}.
|
||||||
* @property {string} main The entry point as defined in the main entry of the manifest.
|
* @property {string} main The entry point as defined in the main entry of the manifest.
|
||||||
|
* @property {string} description The description of plugin as defined in the manifest.
|
||||||
|
* @property {string} icon The icon of plugin as defined in the manifest.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @private */
|
/** @private */
|
||||||
@ -75,6 +77,8 @@ class Plugin {
|
|||||||
this.version = mnf.version
|
this.version = mnf.version
|
||||||
this.activationPoints = mnf.activationPoints || null
|
this.activationPoints = mnf.activationPoints || null
|
||||||
this.main = mnf.main
|
this.main = mnf.main
|
||||||
|
this.description = mnf.description
|
||||||
|
this.icon = mnf.icon
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Package ${this.origin} does not contain a valid manifest: ${error}`)
|
throw new Error(`Package ${this.origin} does not contain a valid manifest: ${error}`)
|
||||||
|
|||||||
5606
electron/core/plugins/data-plugin/package-lock.json
generated
Normal file
5606
electron/core/plugins/data-plugin/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "data-plugin",
|
"name": "data-plugin",
|
||||||
"version": "2.1.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Jan Database Plugin efficiently stores conversation and model data using SQLite, providing accessible data management",
|
||||||
|
"icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/circle-stack.svg",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"author": "Jan",
|
"author": "Jan",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -10,8 +11,8 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -b . && webpack --config webpack.config.js",
|
"build": "tsc -b . && webpack --config webpack.config.js",
|
||||||
"build:package": "rimraf ./data-plugin*.tgz && npm run build && npm pack",
|
"postinstall": "rimraf ./data-plugin*.tgz && node-pre-gyp install --directory=./node_modules/sqlite3 --target_platform=darwin --target_libc=unknown --target_arch=x64 && node-pre-gyp install --directory=./node_modules/sqlite3 --target_platform=darwin --target_libc=unknown --target_arch=arm64 && node-pre-gyp install --directory=./node_modules/sqlite3 --target_platform=linux --target_libc=glibc --target_arch=x64 && node-pre-gyp install --directory=./node_modules/sqlite3 --target_platform=linux --target_libc=musl --target_arch=x64 && node-pre-gyp install --directory=./node_modules/sqlite3 --target_platform=win32 --target_libc=unknown --target_arch=x64 && npm run build",
|
||||||
"build:publish": "npm run build:package && cpx *.tgz ../../pre-install"
|
"build:publish": "npm pack && cpx *.tgz ../../pre-install"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./dist/index.js",
|
".": "./dist/index.js",
|
||||||
@ -36,6 +37,7 @@
|
|||||||
"node_modules"
|
"node_modules"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"node-pre-gyp": "^0.17.0",
|
||||||
"sqlite3": "^5.1.6"
|
"sqlite3": "^5.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,11 +13,11 @@ const dispose = async () =>
|
|||||||
new Promise(async (resolve) => {
|
new Promise(async (resolve) => {
|
||||||
if (window.electronAPI) {
|
if (window.electronAPI) {
|
||||||
window.electronAPI
|
window.electronAPI
|
||||||
.invokePluginFunc(MODULE_PATH, "killSubprocess")
|
.invokePluginFunc(MODULE_PATH, "dispose")
|
||||||
.then((res) => resolve(res));
|
.then((res) => resolve(res));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const inferenceUrl = () => "http://localhost:8080/llama/chat_completion";
|
const inferenceUrl = () => "http://localhost:3928/llama/chat_completion";
|
||||||
|
|
||||||
// Register all the above functions and objects with the relevant extension points
|
// Register all the above functions and objects with the relevant extension points
|
||||||
export function init({ register }) {
|
export function init({ register }) {
|
||||||
|
|||||||
@ -48,10 +48,19 @@ async function initModel(product) {
|
|||||||
// Write the updated config back to the file
|
// Write the updated config back to the file
|
||||||
fs.writeFileSync(configFilePath, JSON.stringify(config, null, 4));
|
fs.writeFileSync(configFilePath, JSON.stringify(config, null, 4));
|
||||||
|
|
||||||
const binaryPath =
|
let binaryName;
|
||||||
process.platform === "win32"
|
|
||||||
? path.join(binaryFolder, "nitro.exe")
|
if (process.platform === "win32") {
|
||||||
: path.join(binaryFolder, "nitro");
|
binaryName = "nitro_windows_amd64.exe";
|
||||||
|
} else if (process.platform === "darwin") { // Mac OS platform
|
||||||
|
binaryName = process.arch === "arm64" ? "nitro_mac_arm64" : "nitro_mac_amd64";
|
||||||
|
} else {
|
||||||
|
// Linux
|
||||||
|
binaryName = "nitro_linux_amd64_cuda"; // For other platforms
|
||||||
|
}
|
||||||
|
|
||||||
|
const binaryPath = path.join(binaryFolder, binaryName);
|
||||||
|
|
||||||
// Execute the binary
|
// Execute the binary
|
||||||
|
|
||||||
subprocess = spawn(binaryPath, [configFilePath], { cwd: binaryFolder });
|
subprocess = spawn(binaryPath, [configFilePath], { cwd: binaryFolder });
|
||||||
@ -72,6 +81,11 @@ async function initModel(product) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dispose() {
|
function dispose() {
|
||||||
|
killSubprocess();
|
||||||
|
// clean other registered resources here
|
||||||
|
}
|
||||||
|
|
||||||
|
function killSubprocess() {
|
||||||
if (subprocess) {
|
if (subprocess) {
|
||||||
subprocess.kill();
|
subprocess.kill();
|
||||||
subprocess = null;
|
subprocess = null;
|
||||||
@ -83,5 +97,6 @@ function dispose() {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
initModel,
|
initModel,
|
||||||
|
killSubprocess,
|
||||||
dispose,
|
dispose,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1 +1,13 @@
|
|||||||
{"custom_config": {"llama_model_path":"","ctx_len":2048,"ngl":100}}
|
{
|
||||||
|
"listeners": [
|
||||||
|
{
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"port": 3928
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_config": {
|
||||||
|
"llama_model_path": "",
|
||||||
|
"ctx_len": 2048,
|
||||||
|
"ngl": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
BIN
electron/core/plugins/inference-plugin/nitro/nitro_linux_amd64_cuda
Executable file
BIN
electron/core/plugins/inference-plugin/nitro/nitro_linux_amd64_cuda
Executable file
Binary file not shown.
BIN
electron/core/plugins/inference-plugin/nitro/nitro_mac_amd64
Executable file
BIN
electron/core/plugins/inference-plugin/nitro/nitro_mac_amd64
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
3673
electron/core/plugins/inference-plugin/package-lock.json
generated
Normal file
3673
electron/core/plugins/inference-plugin/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "inference-plugin",
|
"name": "inference-plugin",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Inference Plugin, powered by @janhq/nitro, bring a high-performance Llama model inference in pure C++.",
|
||||||
|
"icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/command-line.svg",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"author": "James",
|
"author": "Jan",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"activationPoints": [
|
"activationPoints": [
|
||||||
"init"
|
"init"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack.config.js",
|
"build": "webpack --config webpack.config.js",
|
||||||
"build:package": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && rm -rf dist/nitro && cp -r nitro dist/nitro && npm pack",
|
"postinstall": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && rimraf dist/nitro/* && cpx \"nitro/**\" \"dist/nitro\"",
|
||||||
"build:publish": "yarn build:package && cpx *.tgz ../../pre-install"
|
"build:publish": "npm pack && cpx *.tgz ../../pre-install"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cpx": "^1.5.0",
|
"cpx": "^1.5.0",
|
||||||
@ -24,8 +25,7 @@
|
|||||||
"node-llama-cpp"
|
"node-llama-cpp"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-is-dev": "^2.0.0",
|
"electron-is-dev": "^2.0.0"
|
||||||
"node-llama-cpp": "^2.4.1"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
|
|||||||
3582
electron/core/plugins/model-management-plugin/package-lock.json
generated
Normal file
3582
electron/core/plugins/model-management-plugin/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "model-management-plugin",
|
"name": "model-management-plugin",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Model Management Plugin leverages the HuggingFace API for model exploration and seamless downloads",
|
||||||
|
"icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/queue-list.svg",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"author": "James",
|
"author": "James",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -10,8 +11,8 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack.config.js",
|
"build": "webpack --config webpack.config.js",
|
||||||
"build:package": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && npm pack",
|
"postinstall": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\"",
|
||||||
"build:publish": "yarn build:package && cpx *.tgz ../../pre-install"
|
"build:publish": "npm pack && cpx *.tgz ../../pre-install"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cpx": "^1.5.0",
|
"cpx": "^1.5.0",
|
||||||
|
|||||||
1478
electron/core/plugins/monitoring-plugin/package-lock.json
generated
Normal file
1478
electron/core/plugins/monitoring-plugin/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "monitoring-plugin",
|
"name": "monitoring-plugin",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Utilizing systeminformation, it provides essential System and OS information retrieval",
|
||||||
|
"icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/cpu-chip.svg",
|
||||||
"main": "dist/bundle.js",
|
"main": "dist/bundle.js",
|
||||||
"author": "Jan",
|
"author": "Jan",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -10,8 +11,8 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack.config.js",
|
"build": "webpack --config webpack.config.js",
|
||||||
"build:package": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && npm pack",
|
"postinstall": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\"",
|
||||||
"build:publish": "yarn build:package && cpx *.tgz ../../pre-install"
|
"build:publish": "npm pack && cpx *.tgz ../../pre-install"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|||||||
14
electron/entitlements.mac.plist
Normal file
14
electron/entitlements.mac.plist
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?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.allow-dyld-environment-variables</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -6,7 +6,6 @@ import { init } from "./core/plugin-manager/pluginMgr";
|
|||||||
import { setupMenu } from "./utils/menu";
|
import { setupMenu } from "./utils/menu";
|
||||||
import { dispose } from "./utils/disposable";
|
import { dispose } from "./utils/disposable";
|
||||||
|
|
||||||
const isDev = require("electron-is-dev");
|
|
||||||
const request = require("request");
|
const request = require("request");
|
||||||
const progress = require("request-progress");
|
const progress = require("request-progress");
|
||||||
const { autoUpdater } = require("electron-updater");
|
const { autoUpdater } = require("electron-updater");
|
||||||
@ -49,9 +48,9 @@ function createMainWindow() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const startURL = isDev
|
const startURL = app.isPackaged
|
||||||
? "http://localhost:3000"
|
? `file://${join(__dirname, "../renderer/index.html")}`
|
||||||
: `file://${join(__dirname, "../renderer/index.html")}`;
|
: "http://localhost:3000";
|
||||||
|
|
||||||
mainWindow.loadURL(startURL);
|
mainWindow.loadURL(startURL);
|
||||||
|
|
||||||
@ -60,7 +59,7 @@ function createMainWindow() {
|
|||||||
if (process.platform !== "darwin") app.quit();
|
if (process.platform !== "darwin") app.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isDev) mainWindow.webContents.openDevTools();
|
if (!app.isPackaged) mainWindow.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAppUpdates() {
|
function handleAppUpdates() {
|
||||||
@ -127,7 +126,9 @@ function handleIPCs() {
|
|||||||
const basePluginPath = join(
|
const basePluginPath = join(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../",
|
"../",
|
||||||
isDev ? "/core/pre-install" : "../app.asar.unpacked/core/pre-install"
|
app.isPackaged
|
||||||
|
? "../app.asar.unpacked/core/pre-install"
|
||||||
|
: "/core/pre-install"
|
||||||
);
|
);
|
||||||
return readdirSync(basePluginPath)
|
return readdirSync(basePluginPath)
|
||||||
.filter((file) => extname(file) === ".tgz")
|
.filter((file) => extname(file) === ".tgz")
|
||||||
@ -143,6 +144,10 @@ function handleIPCs() {
|
|||||||
ipcMain.handle("openExternalUrl", async (_event, url) => {
|
ipcMain.handle("openExternalUrl", async (_event, url) => {
|
||||||
shell.openExternal(url);
|
shell.openExternal(url);
|
||||||
});
|
});
|
||||||
|
ipcMain.handle("relaunch", async (_event, url) => {
|
||||||
|
dispose(requiredModules);
|
||||||
|
app.relaunch();
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to delete a file from the user data folder
|
* Used to delete a file from the user data folder
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "jan-electron",
|
"name": "jan-electron",
|
||||||
"version": "0.1.1",
|
"version": "0.1.3",
|
||||||
"main": "./build/main.js",
|
"main": "./build/main.js",
|
||||||
"author": "Jan",
|
"author": "Jan <service@jan.ai>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "./",
|
"homepage": "./",
|
||||||
"build": {
|
"build": {
|
||||||
@ -12,7 +12,8 @@
|
|||||||
"renderer/**/*",
|
"renderer/**/*",
|
||||||
"build/*.{js,map}",
|
"build/*.{js,map}",
|
||||||
"build/**/*.{js,map}",
|
"build/**/*.{js,map}",
|
||||||
"core/pre-install"
|
"core/pre-install",
|
||||||
|
"core/plugin-manager/facade"
|
||||||
],
|
],
|
||||||
"asarUnpack": [
|
"asarUnpack": [
|
||||||
"core/pre-install"
|
"core/pre-install"
|
||||||
@ -26,33 +27,45 @@
|
|||||||
],
|
],
|
||||||
"extends": null,
|
"extends": null,
|
||||||
"mac": {
|
"mac": {
|
||||||
"type": "distribution"
|
"type": "distribution",
|
||||||
|
"entitlements": "./entitlements.mac.plist",
|
||||||
|
"entitlementsInherit": "./entitlements.mac.plist",
|
||||||
|
"notarize": {
|
||||||
|
"teamId": "YT49P7GXG4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"artifactName": "${name}-${os}-${arch}-${version}.${ext}"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint . --ext \".js,.jsx,.ts,.tsx\"",
|
"lint": "eslint . --ext \".js,.jsx,.ts,.tsx\"",
|
||||||
|
"test:e2e": "playwright test --workers=1",
|
||||||
"dev": "tsc -p . && electron .",
|
"dev": "tsc -p . && electron .",
|
||||||
"build": "tsc -p . && electron-builder -p never -mw",
|
"build": "tsc -p . && electron-builder -p never -m",
|
||||||
"build:publish": "tsc -p . && electron-builder -p onTagOrDraft -mw",
|
"build:darwin": "tsc -p . && electron-builder -p never -m --x64 --arm64",
|
||||||
"postinstall": "electron-builder install-app-deps"
|
"build:win32": "tsc -p . && electron-builder -p never -w",
|
||||||
|
"build:linux": "tsc -p . && electron-builder -p never --linux deb",
|
||||||
|
"build:publish": "tsc -p . && electron-builder -p onTagOrDraft -m",
|
||||||
|
"build:publish-darwin": "tsc -p . && electron-builder -p onTagOrDraft -m --x64 --arm64",
|
||||||
|
"build:publish-win32": "tsc -p . && electron-builder -p onTagOrDraft -w",
|
||||||
|
"build:publish-linux": "tsc -p . && electron-builder -p onTagOrDraft --linux deb "
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-is-dev": "^2.0.0",
|
"@npmcli/arborist": "^7.1.0",
|
||||||
"electron-store": "^8.1.0",
|
"electron-store": "^8.1.0",
|
||||||
"electron-updater": "^6.1.4",
|
"electron-updater": "^6.1.4",
|
||||||
"node-llama-cpp": "^2.4.1",
|
"pacote": "^17.0.4",
|
||||||
"pluggable-electron": "^0.6.0",
|
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"request-progress": "^3.0.0"
|
"request-progress": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@electron/notarize": "^2.1.0",
|
||||||
|
"@playwright/test": "^1.38.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.7.3",
|
"@typescript-eslint/eslint-plugin": "^6.7.3",
|
||||||
"@typescript-eslint/parser": "^6.7.3",
|
"@typescript-eslint/parser": "^6.7.3",
|
||||||
"concurrently": "^8.2.1",
|
|
||||||
"electron": "26.2.1",
|
"electron": "26.2.1",
|
||||||
"electron-builder": "^24.6.4",
|
"electron-builder": "^24.6.4",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"electron-playwright-helpers": "^1.6.0",
|
||||||
"wait-on": "^7.0.1"
|
"eslint-plugin-react": "^7.33.2"
|
||||||
},
|
},
|
||||||
"installConfig": {
|
"installConfig": {
|
||||||
"hoistingLimits": "workspaces"
|
"hoistingLimits": "workspaces"
|
||||||
|
|||||||
10
electron/playwright.config.ts
Normal file
10
electron/playwright.config.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { PlaywrightTestConfig } from "@playwright/test";
|
||||||
|
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
testDir: "./tests",
|
||||||
|
testIgnore: "./core/**",
|
||||||
|
retries: 0,
|
||||||
|
timeout: 120000,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable react-hooks/rules-of-hooks */
|
|
||||||
// Make Pluggable Electron's facade available to the renderer on window.plugins
|
// Make Pluggable Electron's facade available to the renderer on window.plugins
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const useFacade = require("pluggable-electron/facade");
|
const useFacade = require("../core/plugin-manager/facade");
|
||||||
useFacade();
|
useFacade();
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const { contextBridge, ipcRenderer } = require("electron");
|
const { contextBridge, ipcRenderer } = require("electron");
|
||||||
@ -18,6 +17,8 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
|||||||
|
|
||||||
openExternalUrl: (url: string) => ipcRenderer.invoke("openExternalUrl", url),
|
openExternalUrl: (url: string) => ipcRenderer.invoke("openExternalUrl", url),
|
||||||
|
|
||||||
|
relaunch: () => ipcRenderer.invoke("relaunch"),
|
||||||
|
|
||||||
deleteFile: (filePath: string) => ipcRenderer.invoke("deleteFile", filePath),
|
deleteFile: (filePath: string) => ipcRenderer.invoke("deleteFile", filePath),
|
||||||
|
|
||||||
downloadFile: (url: string, path: string) =>
|
downloadFile: (url: string, path: string) =>
|
||||||
|
|||||||
47
electron/tests/explore.e2e.spec.ts
Normal file
47
electron/tests/explore.e2e.spec.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { _electron as electron } from "playwright";
|
||||||
|
import { ElectronApplication, Page, expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
import {
|
||||||
|
findLatestBuild,
|
||||||
|
parseElectronApp,
|
||||||
|
stubDialog,
|
||||||
|
} from "electron-playwright-helpers";
|
||||||
|
|
||||||
|
let electronApp: ElectronApplication;
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
test.beforeAll(async () => {
|
||||||
|
process.env.CI = "e2e";
|
||||||
|
|
||||||
|
const latestBuild = findLatestBuild("dist");
|
||||||
|
expect(latestBuild).toBeTruthy();
|
||||||
|
|
||||||
|
// parse the packaged Electron app and find paths and other info
|
||||||
|
const appInfo = parseElectronApp(latestBuild);
|
||||||
|
expect(appInfo).toBeTruthy();
|
||||||
|
|
||||||
|
electronApp = await electron.launch({
|
||||||
|
args: [appInfo.main], // main file from package.json
|
||||||
|
executablePath: appInfo.executable, // path to the Electron executable
|
||||||
|
});
|
||||||
|
await stubDialog(electronApp, "showMessageBox", { response: 1 });
|
||||||
|
|
||||||
|
page = await electronApp.firstWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
await electronApp.close();
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("explores models", async () => {
|
||||||
|
await page.getByRole("button", { name: "Explore Models" }).first().click();
|
||||||
|
const header = await page
|
||||||
|
.getByRole("heading")
|
||||||
|
.filter({ hasText: "Explore Models" })
|
||||||
|
.first()
|
||||||
|
.isDisabled();
|
||||||
|
expect(header).toBe(false);
|
||||||
|
|
||||||
|
// More test cases here...
|
||||||
|
});
|
||||||
57
electron/tests/main.e2e.spec.ts
Normal file
57
electron/tests/main.e2e.spec.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { _electron as electron } from "playwright";
|
||||||
|
import { ElectronApplication, Page, expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
import {
|
||||||
|
findLatestBuild,
|
||||||
|
parseElectronApp,
|
||||||
|
stubDialog,
|
||||||
|
} from "electron-playwright-helpers";
|
||||||
|
|
||||||
|
let electronApp: ElectronApplication;
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
test.beforeAll(async () => {
|
||||||
|
process.env.CI = "e2e";
|
||||||
|
|
||||||
|
const latestBuild = findLatestBuild("dist");
|
||||||
|
expect(latestBuild).toBeTruthy();
|
||||||
|
|
||||||
|
// parse the packaged Electron app and find paths and other info
|
||||||
|
const appInfo = parseElectronApp(latestBuild);
|
||||||
|
expect(appInfo).toBeTruthy();
|
||||||
|
expect(appInfo.asar).toBe(true);
|
||||||
|
expect(appInfo.executable).toBeTruthy();
|
||||||
|
expect(appInfo.main).toBeTruthy();
|
||||||
|
expect(appInfo.name).toBe("jan-electron");
|
||||||
|
expect(appInfo.packageJson).toBeTruthy();
|
||||||
|
expect(appInfo.packageJson.name).toBe("jan-electron");
|
||||||
|
expect(appInfo.platform).toBeTruthy();
|
||||||
|
expect(appInfo.platform).toBe(process.platform);
|
||||||
|
expect(appInfo.resourcesDir).toBeTruthy();
|
||||||
|
|
||||||
|
electronApp = await electron.launch({
|
||||||
|
args: [appInfo.main], // main file from package.json
|
||||||
|
executablePath: appInfo.executable, // path to the Electron executable
|
||||||
|
});
|
||||||
|
await stubDialog(electronApp, "showMessageBox", { response: 1 });
|
||||||
|
|
||||||
|
page = await electronApp.firstWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
await electronApp.close();
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders the home page", async () => {
|
||||||
|
expect(page).toBeDefined();
|
||||||
|
|
||||||
|
// Welcome text is available
|
||||||
|
const welcomeText = await page
|
||||||
|
.locator(".text-5xl", {
|
||||||
|
hasText: "Welcome,let’s download your first model",
|
||||||
|
})
|
||||||
|
.first()
|
||||||
|
.isDisabled();
|
||||||
|
expect(welcomeText).toBe(false);
|
||||||
|
});
|
||||||
46
electron/tests/my-models.e2e.spec.ts
Normal file
46
electron/tests/my-models.e2e.spec.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { _electron as electron } from "playwright";
|
||||||
|
import { ElectronApplication, Page, expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
import {
|
||||||
|
findLatestBuild,
|
||||||
|
parseElectronApp,
|
||||||
|
stubDialog,
|
||||||
|
} from "electron-playwright-helpers";
|
||||||
|
|
||||||
|
let electronApp: ElectronApplication;
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
test.beforeAll(async () => {
|
||||||
|
process.env.CI = "e2e";
|
||||||
|
|
||||||
|
const latestBuild = findLatestBuild("dist");
|
||||||
|
expect(latestBuild).toBeTruthy();
|
||||||
|
|
||||||
|
// parse the packaged Electron app and find paths and other info
|
||||||
|
const appInfo = parseElectronApp(latestBuild);
|
||||||
|
expect(appInfo).toBeTruthy();
|
||||||
|
|
||||||
|
electronApp = await electron.launch({
|
||||||
|
args: [appInfo.main], // main file from package.json
|
||||||
|
executablePath: appInfo.executable, // path to the Electron executable
|
||||||
|
});
|
||||||
|
await stubDialog(electronApp, "showMessageBox", { response: 1 });
|
||||||
|
|
||||||
|
page = await electronApp.firstWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
await electronApp.close();
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shows my models", async () => {
|
||||||
|
await page.getByRole("button", { name: "My Models" }).first().click();
|
||||||
|
const header = await page
|
||||||
|
.getByRole("heading")
|
||||||
|
.filter({ hasText: "My Models" })
|
||||||
|
.first()
|
||||||
|
.isDisabled();
|
||||||
|
expect(header).toBe(false);
|
||||||
|
// More test cases here...
|
||||||
|
});
|
||||||
76
electron/tests/navigation.e2e.spec.ts
Normal file
76
electron/tests/navigation.e2e.spec.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { _electron as electron } from "playwright";
|
||||||
|
import { ElectronApplication, Page, expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
import {
|
||||||
|
findLatestBuild,
|
||||||
|
parseElectronApp,
|
||||||
|
stubDialog,
|
||||||
|
} from "electron-playwright-helpers";
|
||||||
|
|
||||||
|
let electronApp: ElectronApplication;
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
test.beforeAll(async () => {
|
||||||
|
process.env.CI = "e2e";
|
||||||
|
|
||||||
|
const latestBuild = findLatestBuild("dist");
|
||||||
|
expect(latestBuild).toBeTruthy();
|
||||||
|
|
||||||
|
// parse the packaged Electron app and find paths and other info
|
||||||
|
const appInfo = parseElectronApp(latestBuild);
|
||||||
|
expect(appInfo).toBeTruthy();
|
||||||
|
|
||||||
|
electronApp = await electron.launch({
|
||||||
|
args: [appInfo.main], // main file from package.json
|
||||||
|
executablePath: appInfo.executable, // path to the Electron executable
|
||||||
|
});
|
||||||
|
await stubDialog(electronApp, "showMessageBox", { response: 1 });
|
||||||
|
|
||||||
|
page = await electronApp.firstWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
await electronApp.close();
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders left navigation panel", async () => {
|
||||||
|
// Chat History section is available
|
||||||
|
const chatSection = await page
|
||||||
|
.getByRole("heading")
|
||||||
|
.filter({ hasText: "CHAT HISTORY" })
|
||||||
|
.first()
|
||||||
|
.isDisabled();
|
||||||
|
expect(chatSection).toBe(false);
|
||||||
|
|
||||||
|
// Home actions
|
||||||
|
const newChatBtn = await page
|
||||||
|
.getByRole("button", { name: "New Chat" })
|
||||||
|
.first()
|
||||||
|
.isEnabled();
|
||||||
|
const exploreBtn = await page
|
||||||
|
.getByRole("button", { name: "Explore Models" })
|
||||||
|
.first()
|
||||||
|
.isEnabled();
|
||||||
|
const discordBtn = await page
|
||||||
|
.getByRole("button", { name: "Discord" })
|
||||||
|
.first()
|
||||||
|
.isEnabled();
|
||||||
|
const myModelsBtn = await page
|
||||||
|
.getByRole("button", { name: "My Models" })
|
||||||
|
.first()
|
||||||
|
.isEnabled();
|
||||||
|
const settingsBtn = await page
|
||||||
|
.getByRole("button", { name: "Settings" })
|
||||||
|
.first()
|
||||||
|
.isEnabled();
|
||||||
|
expect(
|
||||||
|
[
|
||||||
|
newChatBtn,
|
||||||
|
exploreBtn,
|
||||||
|
discordBtn,
|
||||||
|
myModelsBtn,
|
||||||
|
settingsBtn,
|
||||||
|
].filter((e) => !e).length
|
||||||
|
).toBe(0);
|
||||||
|
});
|
||||||
42
electron/tests/settings.e2e.spec.ts
Normal file
42
electron/tests/settings.e2e.spec.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { _electron as electron } from "playwright";
|
||||||
|
import { ElectronApplication, Page, expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
import {
|
||||||
|
findLatestBuild,
|
||||||
|
parseElectronApp,
|
||||||
|
stubDialog,
|
||||||
|
} from "electron-playwright-helpers";
|
||||||
|
|
||||||
|
let electronApp: ElectronApplication;
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
test.beforeAll(async () => {
|
||||||
|
process.env.CI = "e2e";
|
||||||
|
|
||||||
|
const latestBuild = findLatestBuild("dist");
|
||||||
|
expect(latestBuild).toBeTruthy();
|
||||||
|
|
||||||
|
// parse the packaged Electron app and find paths and other info
|
||||||
|
const appInfo = parseElectronApp(latestBuild);
|
||||||
|
expect(appInfo).toBeTruthy();
|
||||||
|
|
||||||
|
electronApp = await electron.launch({
|
||||||
|
args: [appInfo.main], // main file from package.json
|
||||||
|
executablePath: appInfo.executable, // path to the Electron executable
|
||||||
|
});
|
||||||
|
await stubDialog(electronApp, "showMessageBox", { response: 1 });
|
||||||
|
|
||||||
|
page = await electronApp.firstWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
await electronApp.close();
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shows settings", async () => {
|
||||||
|
await page.getByRole("button", { name: "Settings" }).first().click();
|
||||||
|
|
||||||
|
const pluginList = await page.getByTestId("plugin-item").count();
|
||||||
|
expect(pluginList).toBe(4);
|
||||||
|
});
|
||||||
@ -2,13 +2,17 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
"noImplicitAny": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
"rootDir": "./",
|
"rootDir": "./",
|
||||||
"noEmitOnError": true,
|
"noEmitOnError": true,
|
||||||
|
"baseUrl": ".",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
"paths": { "*": ["node_modules/*"] },
|
||||||
"typeRoots": ["node_modules/@types"]
|
"typeRoots": ["node_modules/@types"]
|
||||||
},
|
},
|
||||||
"exclude": ["core", "build", "node_modules"]
|
"include": ["./**/*.ts"],
|
||||||
|
"exclude": ["core", "build", "dist", "tests"]
|
||||||
}
|
}
|
||||||
|
|||||||
14224
package-lock.json
generated
Normal file
14224
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@ -14,19 +14,29 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"lint": "yarn workspace jan-electron lint && yarn workspace jan-web lint",
|
||||||
|
"test": "yarn workspace jan-electron test:e2e",
|
||||||
"dev:electron": "yarn workspace jan-electron dev",
|
"dev:electron": "yarn workspace jan-electron dev",
|
||||||
"dev:web": "yarn workspace jan-web dev",
|
"dev:web": "yarn workspace jan-web dev",
|
||||||
"dev": "concurrently --kill-others-on-fail \"yarn dev:web\" \"wait-on http://localhost:3000 && yarn dev:electron\"",
|
"dev": "concurrently --kill-others \"yarn dev:web\" \"wait-on http://localhost:3000 && yarn dev:electron\"",
|
||||||
"build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"",
|
"build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"",
|
||||||
"build:electron": "yarn workspace jan-electron build",
|
"build:electron": "yarn workspace jan-electron build",
|
||||||
"build:plugins": "rm -f ./electron/core/pre-install/*.tgz && concurrently \"cd ./electron/core/plugins/data-plugin && npm install && npm run build:publish\" \"cd ./electron/core/plugins/inference-plugin && npm install && npm run build:publish\" \"cd ./electron/core/plugins/model-management-plugin && npm install && npm run build:publish\" \"cd ./electron/core/plugins/monitoring-plugin && npm install && npm run build:publish\"",
|
"build:plugins": "rimraf ./electron/core/pre-install/*.tgz && concurrently \"cd ./electron/core/plugins/data-plugin && npm ci\" \"cd ./electron/core/plugins/inference-plugin && npm ci\" \"cd ./electron/core/plugins/model-management-plugin && npm ci\" \"cd ./electron/core/plugins/monitoring-plugin && npm ci\" && concurrently \"cd ./electron/core/plugins/data-plugin && npm run build:publish\" \"cd ./electron/core/plugins/inference-plugin && npm run build:publish\" \"cd ./electron/core/plugins/model-management-plugin && npm run build:publish\" \"cd ./electron/core/plugins/monitoring-plugin && npm run build:publish\"",
|
||||||
|
"build:plugins-darwin": "rimraf ./electron/core/pre-install/*.tgz && concurrently \"cd ./electron/core/plugins/data-plugin && npm ci\" \"cd ./electron/core/plugins/inference-plugin && npm ci\" \"cd ./electron/core/plugins/model-management-plugin && npm ci\" \"cd ./electron/core/plugins/monitoring-plugin && npm ci\" && chmod +x ./electron/auto-sign.sh && ./electron/auto-sign.sh && concurrently \"cd ./electron/core/plugins/data-plugin && npm run build:publish\" \"cd ./electron/core/plugins/inference-plugin && npm run build:publish\" \"cd ./electron/core/plugins/model-management-plugin && npm run build:publish\" \"cd ./electron/core/plugins/monitoring-plugin && npm run build:publish\"",
|
||||||
"build": "yarn build:web && yarn build:electron",
|
"build": "yarn build:web && yarn build:electron",
|
||||||
"build:publish": "yarn build:web && yarn workspace jan-electron build:publish"
|
"build:darwin": "yarn build:web && yarn workspace jan-electron build:darwin",
|
||||||
|
"build:win32": "yarn build:web && yarn workspace jan-electron build:win32",
|
||||||
|
"build:linux": "yarn build:web && yarn workspace jan-electron build:linux",
|
||||||
|
"build:publish": "yarn build:web && yarn workspace jan-electron build:publish",
|
||||||
|
"build:publish-darwin": "yarn build:web && yarn workspace jan-electron build:publish-darwin",
|
||||||
|
"build:publish-win32": "yarn build:web && yarn workspace jan-electron build:publish-win32",
|
||||||
|
"build:publish-linux": "yarn build:web && yarn workspace jan-electron build:publish-linux"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^8.2.1",
|
"concurrently": "^8.2.1",
|
||||||
"cpx": "^1.5.0",
|
"cpx": "^1.5.0",
|
||||||
"wait-on": "^7.0.1"
|
"wait-on": "^7.0.1",
|
||||||
|
"rimraf": "^3.0.2"
|
||||||
},
|
},
|
||||||
"version": "0.0.0"
|
"version": "0.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
plugins,
|
plugins,
|
||||||
extensionPoints,
|
extensionPoints,
|
||||||
activationPoints,
|
activationPoints,
|
||||||
} from "../../../electron/core/plugin-manager/execution/index";
|
} from "@/../../electron/core/plugin-manager/execution/index";
|
||||||
import {
|
import {
|
||||||
ChartPieIcon,
|
ChartPieIcon,
|
||||||
CommandLineIcon,
|
CommandLineIcon,
|
||||||
@ -81,9 +81,7 @@ export const Preferences = () => {
|
|||||||
// Send the filename of the to be installed plugin
|
// Send the filename of the to be installed plugin
|
||||||
// to the main process for installation
|
// to the main process for installation
|
||||||
const installed = await plugins.install([pluginFile]);
|
const installed = await plugins.install([pluginFile]);
|
||||||
if (typeof window !== "undefined") {
|
if (installed) window.electronAPI.relaunch();
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Uninstall a plugin on clicking uninstall
|
// Uninstall a plugin on clicking uninstall
|
||||||
@ -99,6 +97,7 @@ export const Preferences = () => {
|
|||||||
? "Plugin successfully uninstalled"
|
? "Plugin successfully uninstalled"
|
||||||
: "Plugin could not be uninstalled"
|
: "Plugin could not be uninstalled"
|
||||||
);
|
);
|
||||||
|
if (res) window.electronAPI.relaunch();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update all plugins on clicking update plugins
|
// Update all plugins on clicking update plugins
|
||||||
@ -106,6 +105,7 @@ export const Preferences = () => {
|
|||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await window.pluggableElectronIpc.update([plugin], true);
|
await window.pluggableElectronIpc.update([plugin], true);
|
||||||
|
window.electronAPI.relaunch();
|
||||||
}
|
}
|
||||||
// plugins.update(active.map((plg) => plg.name));
|
// plugins.update(active.map((plg) => plg.name));
|
||||||
};
|
};
|
||||||
@ -176,9 +176,7 @@ export const Preferences = () => {
|
|||||||
type="submit"
|
type="submit"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
|
"rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
|
||||||
fileName
|
fileName ? "bg-indigo-600 hover:bg-indigo-500" : "bg-gray-500"
|
||||||
? "bg-indigo-600 hover:bg-indigo-500"
|
|
||||||
: "bg-gray-500"
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Install Plugin
|
Install Plugin
|
||||||
@ -190,7 +188,7 @@ export const Preferences = () => {
|
|||||||
<CommandLineIcon width={30} />
|
<CommandLineIcon width={30} />
|
||||||
Installed Plugins
|
Installed Plugins
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap">
|
<div className="grid grid-cols-2 items-stretch gap-4">
|
||||||
{activePlugins
|
{activePlugins
|
||||||
.filter(
|
.filter(
|
||||||
(e) =>
|
(e) =>
|
||||||
@ -198,19 +196,31 @@ export const Preferences = () => {
|
|||||||
e.name.toLowerCase().includes(search.toLowerCase())
|
e.name.toLowerCase().includes(search.toLowerCase())
|
||||||
)
|
)
|
||||||
.map((e) => (
|
.map((e) => (
|
||||||
<div key={e.name} className="mr-2 my-3 w-[400px]">
|
<div
|
||||||
<a
|
key={e.name}
|
||||||
href="#"
|
data-testid="plugin-item"
|
||||||
className="block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700"
|
className="flex flex-col h-full p-6 bg-white border border-gray-200 rounded-sm dark:border-gray-300"
|
||||||
>
|
>
|
||||||
<h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
|
<div className="flex flex-row space-x-2 items-center">
|
||||||
{e.name}
|
<span className="relative inline-block mt-1">
|
||||||
</h5>
|
<img
|
||||||
<p className="font-normal text-gray-700 dark:text-gray-400">
|
className="h-14 w-14 rounded-md"
|
||||||
Activation: {e.activationPoints}
|
src={e.icon ?? "icons/app_icon.svg"}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<p className="text-xl font-bold tracking-tight text-gray-900 dark:text-white capitalize">
|
||||||
|
{e.name.replaceAll("-", " ")}
|
||||||
</p>
|
</p>
|
||||||
<p className="font-normal text-gray-700 dark:text-gray-400 h-[24px] truncate w-full">
|
<p className="font-normal text-gray-700 dark:text-gray-400">
|
||||||
Url: {e.url}
|
Version: {e.version}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="flex-1 mt-2 text-sm font-normal text-gray-500 dark:text-gray-400 w-full">
|
||||||
|
{e.description ?? "Jan's Plugin"}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-row space-x-5">
|
<div className="flex flex-row space-x-5">
|
||||||
<button
|
<button
|
||||||
@ -218,7 +228,7 @@ export const Preferences = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
uninstall(e.name);
|
uninstall(e.name);
|
||||||
}}
|
}}
|
||||||
className="mt-5 rounded-md bg-red-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
|
className="mt-5 rounded-md bg-red-500 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-red-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
|
||||||
>
|
>
|
||||||
Uninstall
|
Uninstall
|
||||||
</button>
|
</button>
|
||||||
@ -227,12 +237,11 @@ export const Preferences = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
update(e.name);
|
update(e.name);
|
||||||
}}
|
}}
|
||||||
className="mt-5 rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
className="mt-5 rounded-md bg-blue-500 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
|
||||||
>
|
>
|
||||||
Update
|
Update
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -12,6 +12,10 @@ import {
|
|||||||
showingProductDetailAtom,
|
showingProductDetailAtom,
|
||||||
showingAdvancedPromptAtom,
|
showingAdvancedPromptAtom,
|
||||||
} from "@/_helpers/atoms/Modal.atom";
|
} from "@/_helpers/atoms/Modal.atom";
|
||||||
|
import {
|
||||||
|
MainViewState,
|
||||||
|
setMainViewStateAtom,
|
||||||
|
} from "@/_helpers/atoms/MainView.atom";
|
||||||
|
|
||||||
export default function useDeleteConversation() {
|
export default function useDeleteConversation() {
|
||||||
const [userConversations, setUserConversations] = useAtom(
|
const [userConversations, setUserConversations] = useAtom(
|
||||||
@ -23,14 +27,19 @@ export default function useDeleteConversation() {
|
|||||||
const activeConvoId = useAtomValue(getActiveConvoIdAtom);
|
const activeConvoId = useAtomValue(getActiveConvoIdAtom);
|
||||||
const setActiveConvoId = useSetAtom(setActiveConvoIdAtom);
|
const setActiveConvoId = useSetAtom(setActiveConvoIdAtom);
|
||||||
const deleteMessages = useSetAtom(deleteConversationMessage);
|
const deleteMessages = useSetAtom(deleteConversationMessage);
|
||||||
|
const setMainViewState = useSetAtom(setMainViewStateAtom);
|
||||||
|
|
||||||
const deleteConvo = async () => {
|
const deleteConvo = async () => {
|
||||||
if (activeConvoId) {
|
if (activeConvoId) {
|
||||||
try {
|
try {
|
||||||
await execute(DataService.DELETE_CONVERSATION, activeConvoId);
|
await execute(DataService.DELETE_CONVERSATION, activeConvoId);
|
||||||
setUserConversations(
|
const currentConversations = userConversations.filter(
|
||||||
userConversations.filter((c) => c.id !== activeConvoId)
|
(c) => c.id !== activeConvoId
|
||||||
);
|
);
|
||||||
|
setUserConversations(currentConversations);
|
||||||
|
if (currentConversations.length === 0) {
|
||||||
|
setMainViewState(MainViewState.Welcome);
|
||||||
|
}
|
||||||
deleteMessages(activeConvoId);
|
deleteMessages(activeConvoId);
|
||||||
setActiveConvoId(undefined);
|
setActiveConvoId(undefined);
|
||||||
setCurrentPrompt("");
|
setCurrentPrompt("");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user