jan/web/screens/Settings/CoreExtensions/ExtensionItem.tsx
marknguyen1302 a36b3fee24
fix: move Jan folder (#3160)
* chore: upgrade marked-katex-extension (#3049)

* fix: handle long word without space to avoid right panel disappears (#3048)

* add time weighted retrieval (#2908)

* add time weighted retrieval

* add missing configuration for timeWeightedVectorStore

* resolving conflict

* add missing configuration for timeWeightedVectorStore

* resolving conflict

* fix linting issues

* fix build failed due to requirement for useTimeWeightedRetriever in AssistantTool

* update web packages complying the new structure

---------

Co-authored-by: thu <thu@treehouse.finance>

* fix: model dropdown search by configured model (#3047)

* bump version (#3082) (#3083)

Co-authored-by: Hoang Ha <64120343+hahuyhoang411@users.noreply.github.com>

* Update cortex cpp nightly to version 0.4.18 (#3072)

* Update cortex cpp nightly to version 0.4.17

* update linux downloadnitro

* c‌ortex 0.4.18

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Van Pham <64197333+Van-QA@users.noreply.github.com>

* chore: update download.ts (#3088)

infomation -> information

* chore: cortex version update (#3098)

* fix: handle words without space (#3101)

* fix: handle long thread title without space (#3107)

* fix: handle long thread title without space, and make searchbar autofocus inside model dropdown

* feat: enable right click to show setting on thread items (#3108)

* chore: Bump-cortex-0.4.17 (#3111)

* Update cortex cpp nightly to version 0.4.18 (#3114)

* Update cortex cpp nightly to version 0.4.18

* cortex 0.4.19

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Van Pham <64197333+Van-QA@users.noreply.github.com>

* Chore: Add stop token for Gemma 2b (#3125)

* add stop token

* Bump version

* fix: set specific version for terminate (#3126)

Signed-off-by: James <namnh0122@gmail.com>

* feat: add claude 3.5 sonnet (#3129)

Signed-off-by: James <namnh0122@gmail.com>

* feat: add options config spell check for chat input (#3131)

* fixed grammar nits (#3132)

* Update cortex cpp nightly to version 0.4.20

* fix: toggle button for expand log section on modal troubleshoot (#3130)

* fix: add tooltip messages toolbar (#3138)

* fix: handle error message when apikey is not setup (#3149)

* fix: title thread not updated on input edit title (#3148)

* merge dev

* fix move jan folder

* Update electron/preload.ts

* refactor

* Update electron/preload.ts

* fix wrong param

* use correct method

* chore: fix lint

---------

Signed-off-by: James <namnh0122@gmail.com>
Co-authored-by: Faisal Amir <urmauur@gmail.com>
Co-authored-by: Nathan <thu.nhuanh99@gmail.com>
Co-authored-by: thu <thu@treehouse.finance>
Co-authored-by: Van Pham <64197333+Van-QA@users.noreply.github.com>
Co-authored-by: Hoang Ha <64120343+hahuyhoang411@users.noreply.github.com>
Co-authored-by: jan-service-account <136811300+jan-service-account@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
Co-authored-by: NamH <NamNh0122@gmail.com>
Co-authored-by: Saurabh <saurabhrai1717@gmail.com>
Co-authored-by: Louis <louis@jan.ai>
2024-07-15 13:36:52 +07:00

198 lines
5.7 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react'
import {
BaseExtension,
Compatibility,
InstallationState,
abortDownload,
} from '@janhq/core'
import { Button, Progress, Tooltip } from '@janhq/joi'
import { InfoCircledIcon } from '@radix-ui/react-icons'
import { useAtomValue } from 'jotai'
import { Marked, Renderer } from 'marked'
import { extensionManager } from '@/extension'
import { installingExtensionAtom } from '@/helpers/atoms/Extension.atom'
type Props = {
item: BaseExtension
}
const ExtensionItem: React.FC<Props> = ({ item }) => {
const [compatibility, setCompatibility] = useState<Compatibility | undefined>(
undefined
)
const [installState, setInstallState] =
useState<InstallationState>('NotRequired')
const installingExtensions = useAtomValue(installingExtensionAtom)
const isInstalling = installingExtensions.some(
(e) => e.extensionId === item.name
)
const progress = isInstalling
? (installingExtensions.find((e) => e.extensionId === item.name)
?.percentage ?? -1)
: -1
useEffect(() => {
const getExtensionInstallationState = async () => {
const extension = extensionManager.getByName(item.name)
if (!extension) return
if (typeof extension?.installationState === 'function') {
const installState = await extension.installationState()
setInstallState(installState)
}
}
getExtensionInstallationState()
}, [item.name, isInstalling])
useEffect(() => {
const extension = extensionManager.getByName(item.name)
if (!extension) return
setCompatibility(extension.compatibility())
}, [setCompatibility, item.name])
const onInstallClick = useCallback(async () => {
const extension = extensionManager.getByName(item.name)
if (!extension) return
await extension.install()
}, [item.name])
const onCancelInstallingClick = () => {
const extension = installingExtensions.find(
(e) => e.extensionId === item.name
)
if (extension?.localPath) {
abortDownload(extension.localPath)
}
}
const description = marked.parse(item.description ?? '', { async: false })
return (
<div className="mx-4 flex items-start justify-between border-b border-[hsla(var(--app-border))] py-6 first:pt-4 last:border-none">
<div className="flex-1 flex-shrink-0 space-y-1">
<div className="flex items-center gap-x-2">
<h6 className="font-semibold">Additional Dependencies</h6>
</div>
<div
dangerouslySetInnerHTML={{ __html: description }}
className="font-medium leading-relaxed text-[hsla(var(--text-secondary))]"
/>
</div>
<div className="flex min-w-[150px] flex-row justify-end">
<InstallStateIndicator
installProgress={progress}
installState={installState}
compatibility={compatibility}
onInstallClick={onInstallClick}
onCancelClick={onCancelInstallingClick}
/>
</div>
</div>
)
}
type InstallStateProps = {
installProgress: number
compatibility?: Compatibility
installState: InstallationState
onInstallClick: () => void
onCancelClick: () => void
}
const InstallStateIndicator: React.FC<InstallStateProps> = ({
installProgress,
compatibility,
installState,
onInstallClick,
onCancelClick,
}) => {
if (installProgress !== -1) {
const progress = installProgress * 100
return (
<div className="text-primary dark flex h-10 flex-row items-center justify-center space-x-2 rounded-lg px-4">
<button onClick={onCancelClick} className="text-primary font-semibold">
Cancel
</button>
<div className="flex w-[113px] flex-row items-center justify-center space-x-2 rounded-md px-2 py-[2px]">
<Progress className="h-1 w-[69px]" value={progress} />
<span className="text-primary text-xs font-bold">
{progress.toFixed(0)}%
</span>
</div>
</div>
)
}
switch (installState) {
case 'Installed':
return (
<div className="rounded-md px-3 py-1.5 font-semibold text-[hsla(var(--text-secondary))]">
Installed
</div>
)
case 'NotCompatible':
return (
<div className="rounded-md px-3 py-1.5 font-semibold text-[hsla(var(--text-secondary))]">
<div className="flex flex-row items-center justify-center gap-1">
Incompatible
<Tooltip
trigger={
<InfoCircledIcon className="cursor-pointer text-[hsla(var(--text-secondary))]" />
}
content={
compatibility &&
!compatibility['platform']?.includes(PLATFORM) ? (
<span>
Only available on&nbsp;
{compatibility?.platform
?.map((e: string) =>
e === 'win32'
? 'Windows'
: e === 'linux'
? 'Linux'
: 'MacOS'
)
.join(', ')}
</span>
) : (
<span>Your GPUs are not compatible with this extension</span>
)
}
/>
</div>
</div>
)
case 'NotInstalled':
return (
<Button size="small" variant="soft" onClick={onInstallClick}>
Install
</Button>
)
default:
return <div></div>
}
}
const marked: Marked = new Marked({
renderer: {
link: (href, title, text) => {
return Renderer.prototype.link
?.apply(this, [href, title, text])
.replace(
'<a',
"<a class='text-[hsla(var(--app-link))]' target='_blank'"
)
},
},
})
export default ExtensionItem