chore: update hub progress download, added toaster
This commit is contained in:
parent
2345ff172d
commit
53f5729674
@ -10,10 +10,12 @@ import { abortDownload } from '@/services/models'
|
||||
import { getProviders } from '@/services/providers'
|
||||
import { DownloadEvent, DownloadState, events } from '@janhq/core'
|
||||
import { IconX } from '@tabler/icons-react'
|
||||
import { useCallback, useEffect, useMemo } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
export function DownloadManagement() {
|
||||
const { setProviders } = useModelProvider()
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false)
|
||||
const { downloads, updateProgress, removeDownload } = useDownloadStore()
|
||||
const downloadCount = useMemo(
|
||||
() => Object.keys(downloads).length,
|
||||
@ -22,7 +24,7 @@ export function DownloadManagement() {
|
||||
const downloadProcesses = useMemo(
|
||||
() =>
|
||||
Object.values(downloads).map((download) => ({
|
||||
id: download.id,
|
||||
id: download.name,
|
||||
name: download.name,
|
||||
progress: download.progress,
|
||||
current: download.current,
|
||||
@ -76,6 +78,10 @@ export function DownloadManagement() {
|
||||
console.debug('onFileDownloadSuccess', state)
|
||||
removeDownload(state.modelId)
|
||||
getProviders().then(setProviders)
|
||||
toast.success('Download Complete', {
|
||||
id: 'download-complete',
|
||||
description: `The model ${state.modelId} has been downloaded`,
|
||||
})
|
||||
},
|
||||
[removeDownload, setProviders]
|
||||
)
|
||||
@ -107,8 +113,9 @@ export function DownloadManagement() {
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<>
|
||||
{downloadCount > 0 && (
|
||||
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
|
||||
<PopoverTrigger>
|
||||
<div className="bg-left-panel-fg/10 hover:bg-left-panel-fg/12 p-2 rounded-md my-1 relative border border-left-panel-fg/10 cursor-pointer text-left">
|
||||
<div className="bg-primary font-bold size-5 rounded-full absolute -top-2 -right-1 flex items-center justify-center text-primary-fg">
|
||||
@ -123,12 +130,13 @@ export function DownloadManagement() {
|
||||
</div>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
)}
|
||||
|
||||
<PopoverContent
|
||||
side="right"
|
||||
align="end"
|
||||
className="p-0 overflow-hidden text-sm select-none"
|
||||
sideOffset={6}
|
||||
onFocusOutside={(e) => e.preventDefault}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<div className="p-2 py-1.5 bg-main-view-fg/5 border-b border-main-view-fg/6">
|
||||
@ -142,20 +150,29 @@ export function DownloadManagement() {
|
||||
{download.name}
|
||||
</p>
|
||||
<div className="shrink-0 flex items-center space-x-0.5">
|
||||
{/* <IconPlayerPauseFilled
|
||||
size={16}
|
||||
className="text-main-view-fg/70 cursor-pointer"
|
||||
title="Pause download"
|
||||
/> */}
|
||||
<IconX
|
||||
size={16}
|
||||
className="text-main-view-fg/70 cursor-pointer"
|
||||
title="Cancel download"
|
||||
onClick={() => abortDownload(download.name)}
|
||||
onClick={() => {
|
||||
abortDownload(download.name).then(() => {
|
||||
toast.info('Download Cancelled', {
|
||||
id: 'cancel-download',
|
||||
description:
|
||||
'The download process was cancelled',
|
||||
})
|
||||
if (downloadProcesses.length === 0) {
|
||||
setIsPopoverOpen(false)
|
||||
}
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Progress value={download.progress * 100} className="my-2" />
|
||||
<Progress
|
||||
value={download.progress * 100}
|
||||
className="my-2"
|
||||
/>
|
||||
<p className="text-main-view-fg/60 text-xs">
|
||||
{`${renderGB(download.current)} / ${renderGB(download.total)}`}{' '}
|
||||
GB ({download.progress.toFixed(2)}%)
|
||||
@ -166,5 +183,7 @@ export function DownloadManagement() {
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import { downloadModel } from '@/services/models'
|
||||
import { useDownloadStore } from '@/hooks/useDownloadStore'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const Route = createFileRoute(route.hub as any)({
|
||||
@ -77,6 +79,53 @@ function Hub() {
|
||||
setSearchValue(e.target.value)
|
||||
}
|
||||
|
||||
const { downloads } = useDownloadStore()
|
||||
|
||||
const downloadProcesses = useMemo(
|
||||
() =>
|
||||
Object.values(downloads).map((download) => ({
|
||||
id: download.name,
|
||||
name: download.name,
|
||||
progress: download.progress,
|
||||
current: download.current,
|
||||
total: download.total,
|
||||
})),
|
||||
[downloads]
|
||||
)
|
||||
|
||||
interface ModelProps {
|
||||
model: {
|
||||
id: string
|
||||
models: {
|
||||
id: string
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
const DownloadButtonPlaceholder = useMemo(() => {
|
||||
return ({ model }: ModelProps) => {
|
||||
const modelId = model.models[0]?.id
|
||||
const isDownloading = downloadProcesses.some((e) => e.id === modelId)
|
||||
const downloadProgress =
|
||||
downloadProcesses.find((e) => e.id === modelId)?.progress || 0
|
||||
|
||||
return (
|
||||
<>
|
||||
{isDownloading ? (
|
||||
<div className="flex items-center gap-2 w-20">
|
||||
<Progress value={downloadProgress * 100} />
|
||||
<span className="text-xs text-center text-main-view-fg/70">
|
||||
{Math.round(downloadProgress * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<Button onClick={() => downloadModel(modelId)}>Download</Button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
}, [downloadProcesses])
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full">
|
||||
<div className="flex flex-col h-full w-full">
|
||||
@ -134,33 +183,24 @@ function Hub() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col pb-2 mb-2 gap-2">
|
||||
{filteredModels.map((model) => {
|
||||
return (
|
||||
{filteredModels.map((model) => (
|
||||
<div key={model.id}>
|
||||
<Card
|
||||
header={
|
||||
<div className="flex items-center justify-between gap-x-2">
|
||||
<Link
|
||||
to={
|
||||
`https://huggingface.co/${model.id}` as string
|
||||
}
|
||||
to={`https://huggingface.co/${model.id}` as string}
|
||||
target="_blank"
|
||||
>
|
||||
<h1 className="text-main-view-fg font-medium text-base capitalize truncate">
|
||||
{extractModelName(model.id) || ''}
|
||||
</h1>
|
||||
</Link>
|
||||
<div className="shrink-0 space-x-3">
|
||||
<div className="shrink-0 space-x-3 flex items-center">
|
||||
<span className="text-main-view-fg/70 font-medium text-xs">
|
||||
{toGigabytes(model.models?.[0]?.size)}
|
||||
</span>
|
||||
<Button
|
||||
onClick={() =>
|
||||
downloadModel(model.models[0]?.id)
|
||||
}
|
||||
>
|
||||
Download
|
||||
</Button>
|
||||
<DownloadButtonPlaceholder model={model} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@ -177,8 +217,7 @@ function Hub() {
|
||||
),
|
||||
}}
|
||||
content={
|
||||
extractDescription(model.metadata.description) ||
|
||||
''
|
||||
extractDescription(model.metadata.description) || ''
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@ -222,11 +261,9 @@ function Hub() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{expandedModels[model.id] &&
|
||||
model.models.length > 0 && (
|
||||
{expandedModels[model.id] && model.models.length > 0 && (
|
||||
<div className="mt-5">
|
||||
{model.models.map((variant) => {
|
||||
return (
|
||||
{model.models.slice(1).map((variant) => (
|
||||
<CardItem
|
||||
key={variant.id}
|
||||
title={variant.id}
|
||||
@ -236,9 +273,32 @@ function Hub() {
|
||||
<p className="text-main-view-fg/70 font-medium text-xs">
|
||||
{toGigabytes(variant.size)}
|
||||
</p>
|
||||
{(() => {
|
||||
const isDownloading =
|
||||
downloadProcesses.some(
|
||||
(e) => e.id === variant.id
|
||||
)
|
||||
const downloadProgress =
|
||||
downloadProcesses.find(
|
||||
(e) => e.id === variant.id
|
||||
)?.progress || 0
|
||||
|
||||
return isDownloading ? (
|
||||
<>
|
||||
<div className="flex items-center gap-2 w-20">
|
||||
<Progress
|
||||
value={downloadProgress * 100}
|
||||
/>
|
||||
<span className="text-xs text-center text-main-view-fg/70">
|
||||
{Math.round(downloadProgress * 100)}
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div
|
||||
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
||||
title="Edit All Servers JSON"
|
||||
title="Download model"
|
||||
onClick={() =>
|
||||
downloadModel(variant.id)
|
||||
}
|
||||
@ -248,17 +308,17 @@ function Hub() {
|
||||
className="text-main-view-fg/80"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user