feat(ui): AI Tools modal, one-button lane tool picker, AgentHub settings in Overview, markdown preview
- AI Tools moves from a Settings section into a modal behind a button at the Settings tab bar's right edge (AiToolsModal, `actions` on PageTabs, /settings#ai-tools); rows get an enable switch, Default badge, and an Update button for every tool whose catalog names an updater (no version lookup on open); not-installed tools fold behind a disclosure, a finished job's log folds to one line; shared AiToolIcon - codex updates through its own `codex update`, openclaw/hermes gain `update --yes`; update-all runs every installed updater and skips an npm one only when npm does not manage the binary - Add-lane tool picker is one button showing the chosen tool that opens the enabled tools as buttons - Claude Code / Codex AgentHub sub-tab folded into Overview (home editor, hooks, pricing); the path list drops CLAUDE_HOME/CODEX_HOME; HomeDirSetting shows the saved value only while the field differs - Preview/Raw toggle for markdown files in the config FileViewer and the Changes panel's whole-file view (MarkdownPreview: react-markdown + remark-gfm, raw HTML never run, frontmatter as a code block) - docs and the CLAUDE.md marker updated
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* @file SettingsHub.tsx
|
||||
* @description Tabbed shell for /settings that hosts the dashboard's own settings plus one configuration panel per AI tool (Claude Code, Codex and Antigravity) plus the AI Router profiles they can be pointed at and the git logins dashboard fetch/pull/push use, with the active tab kept in the `?tool=` query param. A tool's tab is hidden while that tool is disabled in Settings → AI Tools.
|
||||
* @description Tabbed shell for /settings that hosts the dashboard's own settings plus one configuration panel per AI tool (Claude Code, Codex and Antigravity) plus the AI Router profiles they can be pointed at and the git logins dashboard fetch/pull/push use, with the active tab kept in the `?tool=` query param. The **AI Tools** button at the bar's right edge opens `AiToolsModal` (also opened by `/settings#ai-tools`, the Add-lane modal's link); a tool's tab is hidden while that tool is disabled there.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
import type { ComponentType } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { useCallback, useEffect, useState, type ComponentType } from "react";
|
||||
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Bot,
|
||||
Boxes,
|
||||
KeyRound,
|
||||
Orbit,
|
||||
@@ -22,6 +23,7 @@ import { AntigravityConfig } from "./AntigravityConfig";
|
||||
import { AiRouterConfig } from "./AiRouterConfig";
|
||||
import { GitCredentialsConfig } from "./GitCredentialsConfig";
|
||||
import { useAiTools } from "../hooks/useAiTools";
|
||||
import { AiToolsModal } from "../components/settings/AiToolsModal";
|
||||
|
||||
interface ToolTab {
|
||||
id: string;
|
||||
@@ -85,6 +87,19 @@ export function SettingsHub() {
|
||||
(tab) => !tab.aiTool || aiTools.byId(tab.aiTool)?.enabled !== false
|
||||
);
|
||||
const active = tabs.find((tab) => tab.id === requested) ?? DASHBOARD_TAB;
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const [aiToolsOpen, setAiToolsOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (location.hash === "#ai-tools") setAiToolsOpen(true);
|
||||
}, [location.hash]);
|
||||
|
||||
const closeAiTools = useCallback(() => {
|
||||
setAiToolsOpen(false);
|
||||
// Drop the deep link, or a reload would open the modal again.
|
||||
if (location.hash) navigate({ search: location.search }, { replace: true });
|
||||
}, [location.hash, location.search, navigate]);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -97,9 +112,21 @@ export function SettingsHub() {
|
||||
Icon,
|
||||
label: t(labelKey),
|
||||
}))}
|
||||
actions={
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setAiToolsOpen(true)}
|
||||
aria-haspopup="dialog"
|
||||
className="inline-flex items-center gap-1.5 whitespace-nowrap rounded-lg border border-border px-3 py-1.5 text-xs text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg-primary"
|
||||
>
|
||||
<Bot className="h-3.5 w-3.5" />
|
||||
{t("aiTools.title")}
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
|
||||
<active.Panel />
|
||||
{aiToolsOpen && <AiToolsModal onClose={closeAiTools} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user