chore: Extension should have product name in manifest (#2675)

* chore: Extension should have product name in manifest

* chore: typo
This commit is contained in:
Louis 2024-04-11 09:50:58 +07:00 committed by GitHub
parent d93d74c86b
commit b19234ed71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 60 additions and 31 deletions

View File

@ -40,7 +40,10 @@ export abstract class BaseExtension implements ExtensionType {
protected settingFileName = 'settings.json' protected settingFileName = 'settings.json'
/** @type {string} Name of the extension. */ /** @type {string} Name of the extension. */
name?: string name: string
/** @type {string} Product Name of the extension. */
productName?: string
/** @type {string} The URL of the extension to load. */ /** @type {string} The URL of the extension to load. */
url: string url: string
@ -56,12 +59,14 @@ export abstract class BaseExtension implements ExtensionType {
constructor( constructor(
url: string, url: string,
name?: string, name: string,
productName?: string,
active?: boolean, active?: boolean,
description?: string, description?: string,
version?: string version?: string
) { ) {
this.name = name this.name = name
this.productName = productName
this.url = url this.url = url
this.active = active this.active = active
this.description = description this.description = description

View File

@ -11,6 +11,7 @@ export default class Extension {
* @property {string} origin Original specification provided to fetch the package. * @property {string} origin Original specification provided to fetch the package.
* @property {Object} installOptions Options provided to pacote when fetching the manifest. * @property {Object} installOptions Options provided to pacote when fetching the manifest.
* @property {name} name The name of the extension as defined in the manifest. * @property {name} name The name of the extension as defined in the manifest.
* @property {name} productName The display name of the extension as defined in the manifest.
* @property {string} url Electron URL where the package can be accessed. * @property {string} url Electron URL where the package can be accessed.
* @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 {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.
@ -19,6 +20,7 @@ export default class Extension {
origin?: string origin?: string
installOptions: any installOptions: any
name?: string name?: string
productName?: string
url?: string url?: string
version?: string version?: string
main?: string main?: string
@ -42,7 +44,7 @@ export default class Extension {
const Arborist = require('@npmcli/arborist') const Arborist = require('@npmcli/arborist')
const defaultOpts = { const defaultOpts = {
version: false, version: false,
fullMetadata: false, fullMetadata: true,
Arborist, Arborist,
} }
@ -77,6 +79,7 @@ export default class Extension {
return pacote.manifest(this.specifier, this.installOptions).then((mnf) => { return pacote.manifest(this.specifier, this.installOptions).then((mnf) => {
// set the Package properties based on the it's manifest // set the Package properties based on the it's manifest
this.name = mnf.name this.name = mnf.name
this.productName = mnf.productName as string | undefined
this.version = mnf.version this.version = mnf.version
this.main = mnf.main this.main = mnf.main
this.description = mnf.description this.description = mnf.description

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/assistant-extension", "name": "@janhq/assistant-extension",
"productName": "Jan Assistant Extension",
"version": "1.0.1", "version": "1.0.1",
"description": "This extension enables assistants, including Jan, a default assistant that can call all downloaded models", "description": "This extension enables assistants, including Jan, a default assistant that can call all downloaded models",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/conversational-extension", "name": "@janhq/conversational-extension",
"productName": "Conversational Extension",
"version": "1.0.0", "version": "1.0.0",
"description": "This extension enables conversations and state persistence via your filesystem", "description": "This extension enables conversations and state persistence via your filesystem",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/huggingface-extension", "name": "@janhq/huggingface-extension",
"productName": "HuggingFace Extension",
"version": "1.0.0", "version": "1.0.0",
"description": "Hugging Face extension for converting HF models to GGUF", "description": "Hugging Face extension for converting HF models to GGUF",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/inference-groq-extension", "name": "@janhq/inference-groq-extension",
"productName": "Groq Inference Engine Extension",
"version": "1.0.0", "version": "1.0.0",
"description": "This extension enables fast Groq chat completion API calls", "description": "This extension enables fast Groq chat completion API calls",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/inference-mistral-extension", "name": "@janhq/inference-mistral-extension",
"productName": "Mistral AI Inference Engine Extension",
"version": "1.0.0", "version": "1.0.0",
"description": "This extension enables Mistral chat completion API calls", "description": "This extension enables Mistral chat completion API calls",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/inference-nitro-extension", "name": "@janhq/inference-nitro-extension",
"productName": "Nitro Inference Engine Extension",
"version": "1.0.0", "version": "1.0.0",
"description": "This extension embeds Nitro, a lightweight (3mb) inference engine written in C++. See https://nitro.jan.ai.\nUse this setting if you encounter errors related to **CUDA toolkit** during application execution.", "description": "This extension embeds Nitro, a lightweight (3mb) inference engine written in C++. See https://nitro.jan.ai.\nUse this setting if you encounter errors related to **CUDA toolkit** during application execution.",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/inference-openai-extension", "name": "@janhq/inference-openai-extension",
"productName": "OpenAI Inference Engine Extension",
"version": "1.0.0", "version": "1.0.0",
"description": "This extension enables OpenAI chat completion API calls", "description": "This extension enables OpenAI chat completion API calls",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/inference-triton-trt-llm-extension", "name": "@janhq/inference-triton-trt-llm-extension",
"productName": "Triton-TRT-LLM Inference Engine Extension",
"version": "1.0.0", "version": "1.0.0",
"description": "This extension enables Nvidia's TensorRT-LLM as an inference engine option", "description": "This extension enables Nvidia's TensorRT-LLM as an inference engine option",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/model-extension", "name": "@janhq/model-extension",
"productName": "Model Management Extension",
"version": "1.0.30", "version": "1.0.30",
"description": "Model Management Extension provides model exploration and seamless downloads", "description": "Model Management Extension provides model exploration and seamless downloads",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/monitoring-extension", "name": "@janhq/monitoring-extension",
"productName": "System Monitoring Extension",
"version": "1.0.10", "version": "1.0.10",
"description": "This extension provides system health and OS level data", "description": "This extension provides system health and OS level data",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -1,5 +1,6 @@
{ {
"name": "@janhq/tensorrt-llm-extension", "name": "@janhq/tensorrt-llm-extension",
"productName": "TensorRT-LLM Inference Engine Extension",
"version": "0.0.3", "version": "0.0.3",
"description": "This extension enables Nvidia's TensorRT-LLM for the fastest GPU acceleration. See the [setup guide](https://jan.ai/guides/providers/tensorrt-llm/) for next steps.", "description": "This extension enables Nvidia's TensorRT-LLM for the fastest GPU acceleration. See the [setup guide](https://jan.ai/guides/providers/tensorrt-llm/) for next steps.",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -3,7 +3,10 @@
*/ */
class Extension { class Extension {
/** @type {string} Name of the extension. */ /** @type {string} Name of the extension. */
name?: string name: string
/** @type {string} Product name of the extension. */
productName?: string
/** @type {string} The URL of the extension to load. */ /** @type {string} The URL of the extension to load. */
url: string url: string
@ -19,12 +22,14 @@ class Extension {
constructor( constructor(
url: string, url: string,
name?: string, name: string,
productName?: string,
active?: boolean, active?: boolean,
description?: string, description?: string,
version?: string version?: string
) { ) {
this.name = name this.name = name
this.productName = productName
this.url = url this.url = url
this.active = active this.active = active
this.description = description this.description = description

View File

@ -106,6 +106,7 @@ export class ExtensionManager {
new Extension( new Extension(
ext.url, ext.url,
ext.name, ext.name,
ext.productName,
ext.active, ext.active,
ext.description, ext.description,
ext.version ext.version
@ -135,10 +136,11 @@ export class ExtensionManager {
extensionClass.default.prototype extensionClass.default.prototype
) { ) {
this.register( this.register(
extension.name ?? extension.url, extension.name,
new extensionClass.default( new extensionClass.default(
extension.url, extension.url,
extension.name, extension.name,
extension.productName,
extension.active, extension.active,
extension.description, extension.description,
extension.version extension.version

View File

@ -202,7 +202,7 @@ const Advanced = () => {
</h6> </h6>
</div> </div>
<p className="leading-relaxed"> <p className="leading-relaxed">
Enable experimental features that may be unstable tested. Enable experimental features that may be untested and unstable.
</p> </p>
</div> </div>
<Switch <Switch

View File

@ -46,7 +46,7 @@ const ExtensionItem: React.FC<Props> = ({ item }) => {
useEffect(() => { useEffect(() => {
const getExtensionInstallationState = async () => { const getExtensionInstallationState = async () => {
const extension = extensionManager.getByName(item.name ?? '') const extension = extensionManager.getByName(item.name)
if (!extension) return if (!extension) return
if (typeof extension?.installationState === 'function') { if (typeof extension?.installationState === 'function') {
@ -59,13 +59,13 @@ const ExtensionItem: React.FC<Props> = ({ item }) => {
}, [item.name, isInstalling]) }, [item.name, isInstalling])
useEffect(() => { useEffect(() => {
const extension = extensionManager.getByName(item.name ?? '') const extension = extensionManager.getByName(item.name)
if (!extension) return if (!extension) return
setCompatibility(extension.compatibility()) setCompatibility(extension.compatibility())
}, [setCompatibility, item.name]) }, [setCompatibility, item.name])
const onInstallClick = useCallback(async () => { const onInstallClick = useCallback(async () => {
const extension = extensionManager.getByName(item.name ?? '') const extension = extensionManager.getByName(item.name)
if (!extension) return if (!extension) return
await extension.install() await extension.install()

View File

@ -85,14 +85,10 @@ const ExtensionCatalog = () => {
> >
<div className="w-4/5 flex-shrink-0 space-y-1.5"> <div className="w-4/5 flex-shrink-0 space-y-1.5">
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
<h6 className="text-sm font-semibold capitalize"> <h6 className="text-sm font-semibold">
{formatExtensionsName( {item.productName ?? formatExtensionsName(item.name)} v
item.name ?? item.description ?? '' {item.version}
)}
</h6> </h6>
<p className="whitespace-pre-wrap text-sm font-semibold leading-relaxed ">
v{item.version}
</p>
</div> </div>
<p className="whitespace-pre-wrap leading-relaxed "> <p className="whitespace-pre-wrap leading-relaxed ">
{item.description} {item.description}
@ -110,7 +106,7 @@ const ExtensionCatalog = () => {
</h6> </h6>
</div> </div>
<p className="whitespace-pre-wrap leading-relaxed "> <p className="whitespace-pre-wrap leading-relaxed ">
Select a extension file to install (.tgz) Select an extension file to install (.tgz)
</p> </p>
</div> </div>
<div> <div>

View File

@ -5,16 +5,14 @@ import { useAtom } from 'jotai'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { formatExtensionsName } from '@/utils/converter'
import { selectedSettingAtom } from '@/helpers/atoms/Setting.atom' import { selectedSettingAtom } from '@/helpers/atoms/Setting.atom'
type Props = { type Props = {
name: string
setting: string setting: string
extension?: boolean
} }
const SettingItem: React.FC<Props> = ({ setting, extension = false }) => { const SettingItem: React.FC<Props> = ({ name, setting }) => {
const [selectedSetting, setSelectedSetting] = useAtom(selectedSettingAtom) const [selectedSetting, setSelectedSetting] = useAtom(selectedSettingAtom)
const isActive = selectedSetting === setting const isActive = selectedSetting === setting
@ -28,7 +26,7 @@ const SettingItem: React.FC<Props> = ({ setting, extension = false }) => {
onClick={onSettingItemClick} onClick={onSettingItemClick}
> >
<span className={twMerge(isActive && 'relative z-10', 'capitalize')}> <span className={twMerge(isActive && 'relative z-10', 'capitalize')}>
{extension ? formatExtensionsName(setting) : setting} {name}
</span> </span>
{isActive && ( {isActive && (

View File

@ -11,11 +11,13 @@ import { janSettingScreenAtom } from '@/helpers/atoms/Setting.atom'
const SettingMenu: React.FC = () => { const SettingMenu: React.FC = () => {
const settingScreens = useAtomValue(janSettingScreenAtom) const settingScreens = useAtomValue(janSettingScreenAtom)
const [extensionHasSettings, setExtensionHasSettings] = useState<string[]>([]) const [extensionHasSettings, setExtensionHasSettings] = useState<
{ name?: string; setting: string }[]
>([])
useEffect(() => { useEffect(() => {
const getAllSettings = async () => { const getAllSettings = async () => {
const extensionsMenu: string[] = [] const extensionsMenu: { name?: string; setting: string }[] = []
const extensions = extensionManager.getAll() const extensions = extensionManager.getAll()
for (const extension of extensions) { for (const extension of extensions) {
if (typeof extension.getSettings === 'function') { if (typeof extension.getSettings === 'function') {
@ -24,7 +26,10 @@ const SettingMenu: React.FC = () => {
(settings && settings.length > 0) || (settings && settings.length > 0) ||
(await extension.installationState()) !== 'NotRequired' (await extension.installationState()) !== 'NotRequired'
) { ) {
extensionsMenu.push(extension.name ?? extension.url) extensionsMenu.push({
name: extension.productName,
setting: extension.name,
})
} }
} }
} }
@ -38,7 +43,11 @@ const SettingMenu: React.FC = () => {
<ScrollArea className="h-full w-full"> <ScrollArea className="h-full w-full">
<div className="flex-shrink-0 px-6 py-4 font-medium"> <div className="flex-shrink-0 px-6 py-4 font-medium">
{settingScreens.map((settingScreen) => ( {settingScreens.map((settingScreen) => (
<SettingItem key={settingScreen} setting={settingScreen} /> <SettingItem
key={settingScreen}
name={settingScreen}
setting={settingScreen}
/>
))} ))}
{extensionHasSettings.length > 0 && ( {extensionHasSettings.length > 0 && (
@ -49,11 +58,11 @@ const SettingMenu: React.FC = () => {
</div> </div>
)} )}
{extensionHasSettings.map((extensionName: string) => ( {extensionHasSettings.map((item) => (
<SettingItem <SettingItem
key={extensionName} key={item.name}
setting={extensionName} name={item.name ?? item.setting}
extension={true} setting={item.setting}
/> />
))} ))}
</div> </div>