import { useEffect, useMemo, useState } from 'react' import { useNavigate } from '@tanstack/react-router' import { Boxes, CheckCircle2, Info, Package, Plus, RefreshCw, Terminal as TerminalIcon, Trash2, Zap, } from 'lucide-react' import { api, type MiseLanguage } from '@/api' import { useMiseList } from '@/api/hooks' import { Button, Card, Input, Modal, PageHeader, Select, Tabs } from '@/components/ui' import { toast } from '@/lib/toast' import { cn } from '@/lib/utils' type DisplayLang = MiseLanguage & { sourceText: string } function sourceText(source: MiseLanguage['source']) { if (!source) return '-' if (typeof source === 'string') return source return source.path || source.type || '-' } export default function Languages() { const navigate = useNavigate() const [tab, setTab] = useState<'runtimes' | 'envs'>('runtimes') const [installOpen, setInstallOpen] = useState(false) const [plugins, setPlugins] = useState([]) const [versions, setVersions] = useState([]) const [plugin, setPlugin] = useState('python') const [version, setVersion] = useState('') const [cmdOpen, setCmdOpen] = useState(false) const [command, setCommand] = useState('') const [envs, setEnvs] = useState>({}) const [envKey, setEnvKey] = useState('') const [envValue, setEnvValue] = useState('') const [busy, setBusy] = useState(false) const [message, setMessage] = useState('') const [showTip, setShowTip] = useState(() => localStorage.getItem('taskpool_show_mise_extension_tip') !== '0') const { data, isLoading, refetch, isFetching } = useMiseList() const list: DisplayLang[] = useMemo( () => (Array.isArray(data) ? data : []).map((item) => ({ ...item, sourceText: sourceText(item.source), })), [data], ) useEffect(() => { if (tab !== 'envs') return api.mise .getEnvs() .then((res) => setEnvs(res || {})) .catch(() => setEnvs({})) }, [tab]) useEffect(() => { if (!installOpen) return api.mise .plugins() .then((res) => { const arr = Array.isArray(res) ? res : [] setPlugins(arr) if (arr.length && !arr.includes(plugin)) setPlugin(arr[0]!) }) .catch(() => setPlugins(['python', 'node', 'go', 'php', 'ruby'])) }, [installOpen]) useEffect(() => { if (!installOpen || !plugin) return setVersions([]) setVersion('') api.mise .versions(plugin) .then((res) => { const arr = Array.isArray(res) ? res : [] setVersions(arr) if (arr[0]) setVersion(arr[0]) }) .catch(() => setVersions([])) }, [installOpen, plugin]) async function sync() { setBusy(true) try { await api.mise.sync() setMessage('本地环境同步成功') toast.success('本地环境同步成功') refetch() } catch (e: any) { setMessage(e?.message || '同步失败') toast.error(e?.message || '同步失败') } finally { setBusy(false) } } function openInstallCmd() { if (!plugin || !version) return setCommand(`mise install ${plugin}@${version}`) setInstallOpen(false) setCmdOpen(true) } function uninstallCmd(lang: DisplayLang) { setCommand(`mise uninstall ${lang.plugin}@${lang.version}`) setCmdOpen(true) } async function verify(lang: DisplayLang) { try { const res = await api.mise.verifyCommand(lang.plugin, lang.version) setCommand(res.command) setCmdOpen(true) } catch (e: any) { setMessage(e?.message || '获取验证命令失败') } } async function toggleDefault(lang: DisplayLang) { setBusy(true) try { if (lang.is_global) { await api.mise.unsetGlobal(lang.plugin, lang.version) setMessage(`已取消 ${lang.plugin} 的全局默认`) } else { await api.mise.useGlobal(lang.plugin, lang.version) setMessage(`已将 ${lang.plugin} ${lang.version} 设为全局默认`) } refetch() } catch (e: any) { setMessage(e?.message || '操作失败') } finally { setBusy(false) } } async function saveEnv() { if (!envKey.trim()) return setBusy(true) try { await api.mise.setEnv(envKey.trim(), envValue) setEnvKey('') setEnvValue('') const res = await api.mise.getEnvs() setEnvs(res || {}) setMessage('环境变量已保存') } catch (e: any) { setMessage(e?.message || '保存失败') } finally { setBusy(false) } } async function removeEnv(key: string) { setBusy(true) try { await api.mise.unsetEnv(key) const res = await api.mise.getEnvs() setEnvs(res || {}) } catch (e: any) { setMessage(e?.message || '删除失败') } finally { setBusy(false) } } function closeTip() { setShowTip(false) localStorage.setItem('taskpool_show_mise_extension_tip', '0') } return (
} /> {message ? (
{message}
) : null}
设为默认:将选定版本设为系统全局默认,未指定环境的任务将调用此版本。
{showTip ? (
Mise 也可管理其它工具插件,可在终端安装后通过同步展示。
) : null}
setTab(v as 'runtimes' | 'envs')} items={[ { value: 'runtimes', label: '运行时' }, { value: 'envs', label: '加速/环境' }, ]} />
{tab === 'runtimes' ? ( {isLoading ? (
加载中...
) : list.length === 0 ? (
暂无语言运行时,点击「新增语言」安装
) : (
{list.map((lang, idx) => (
{lang.plugin} {lang.version} {lang.is_global ? ( 默认 ) : null}
来源: {lang.sourceText} · {lang.install_path || '-'}
))}
)}
) : (
Mise 环境变量(镜像加速等)
setEnvKey(e.target.value)} /> setEnvValue(e.target.value)} />
{Object.keys(envs).length === 0 ? (
暂无环境变量
) : (
{Object.entries(envs).map(([k, v]) => (
{k}
{v}
))}
)}
)} setInstallOpen(false)} footer={ <> } >
setCmdOpen(false)} size="lg" footer={ <> } >
{command}

请在「终端命令」页面或系统终端执行上述命令。

) }