mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-06 16:31:12 +08:00
feat: 增加DeepWiki页面和侧边栏导航支持,更新Hook管理功能以支持作用域和索引
This commit is contained in:
@@ -3,12 +3,11 @@
|
||||
// ========================================
|
||||
// Displays DeepWiki documentation content with table of contents
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useMemo, useState, useCallback } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { FileText, Hash, Clock, Sparkles, AlertCircle, Link2, Check } from 'lucide-react';
|
||||
import { Card } from '@/components/ui/Card';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { DeepWikiSymbol, DeepWikiDoc } from '@/hooks/useDeepWiki';
|
||||
|
||||
@@ -276,20 +275,41 @@ export function DocumentViewer({
|
||||
</h4>
|
||||
<nav className="space-y-1">
|
||||
{symbols.map(symbol => (
|
||||
<a
|
||||
<div
|
||||
key={symbol.name}
|
||||
href={`#${symbol.anchor.replace('#', '')}`}
|
||||
className={cn(
|
||||
'block text-xs py-1.5 px-2 rounded transition-colors',
|
||||
'text-muted-foreground hover:text-foreground hover:bg-muted/50',
|
||||
'font-mono'
|
||||
)}
|
||||
className="group flex items-center gap-1"
|
||||
>
|
||||
<span className={cn('mr-1', getSymbolTypeColor(symbol.type))}>
|
||||
{getSymbolTypeIcon(symbol.type)}
|
||||
</span>
|
||||
{symbol.name}
|
||||
</a>
|
||||
<a
|
||||
href={`#${symbol.anchor.replace('#', '')}`}
|
||||
className={cn(
|
||||
'flex-1 text-xs py-1.5 px-2 rounded transition-colors',
|
||||
'text-muted-foreground hover:text-foreground hover:bg-muted/50',
|
||||
'font-mono'
|
||||
)}
|
||||
>
|
||||
<span className={cn('mr-1', getSymbolTypeColor(symbol.type))}>
|
||||
{getSymbolTypeIcon(symbol.type)}
|
||||
</span>
|
||||
{symbol.name}
|
||||
</a>
|
||||
<button
|
||||
onClick={() => copyDeepLink(symbol.name, symbol.anchor)}
|
||||
className={cn(
|
||||
'opacity-0 group-hover:opacity-100 p-1 rounded transition-all',
|
||||
'hover:bg-muted/50',
|
||||
copiedSymbol === symbol.name
|
||||
? 'text-green-500'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
)}
|
||||
title={copiedSymbol === symbol.name ? 'Copied!' : 'Copy deep link'}
|
||||
>
|
||||
{copiedSymbol === symbol.name ? (
|
||||
<Check className="w-3 h-3" />
|
||||
) : (
|
||||
<Link2 className="w-3 h-3" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -30,6 +30,8 @@ export interface HookCardData {
|
||||
matcher?: string;
|
||||
command?: string;
|
||||
script?: string;
|
||||
scope?: 'global' | 'project';
|
||||
index?: number;
|
||||
}
|
||||
|
||||
export interface HookCardProps {
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
FileSearch,
|
||||
ScrollText,
|
||||
Clock,
|
||||
BookOpen,
|
||||
} from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
@@ -92,6 +93,7 @@ const navGroupDefinitions: NavGroupDef[] = [
|
||||
icon: Brain,
|
||||
items: [
|
||||
{ path: '/memory', labelKey: 'navigation.main.memory', icon: Brain },
|
||||
{ path: '/deepwiki', labelKey: 'navigation.main.deepwiki', icon: BookOpen },
|
||||
{ path: '/skills', labelKey: 'navigation.main.skills', icon: Sparkles },
|
||||
{ path: '/commands', labelKey: 'navigation.main.commands', icon: Terminal },
|
||||
{ path: '/settings/rules', labelKey: 'navigation.main.rules', icon: Shield },
|
||||
|
||||
@@ -514,23 +514,33 @@ export function useToggleHook() {
|
||||
|
||||
export function useDeleteHook() {
|
||||
const queryClient = useQueryClient();
|
||||
const projectPath = useWorkflowStore(selectProjectPath);
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: (hookName: string) => deleteHook(hookName),
|
||||
onMutate: async (hookName) => {
|
||||
mutationFn: (hook: { name: string; scope?: 'global' | 'project'; trigger: string; index?: number }) => {
|
||||
const scope = hook.scope || 'project';
|
||||
const hookIndex = hook.index ?? 0;
|
||||
return deleteHook({
|
||||
projectPath: projectPath || undefined,
|
||||
scope,
|
||||
event: hook.trigger,
|
||||
hookIndex,
|
||||
});
|
||||
},
|
||||
onMutate: async (hook) => {
|
||||
await queryClient.cancelQueries({ queryKey: hooksKeys.all });
|
||||
const previousHooks = queryClient.getQueryData<HooksResponse>(hooksKeys.lists());
|
||||
|
||||
queryClient.setQueryData<HooksResponse>(hooksKeys.lists(), (old) => {
|
||||
if (!old) return old;
|
||||
return {
|
||||
hooks: old.hooks.filter((h) => h.name !== hookName),
|
||||
hooks: old.hooks.filter((h) => h.name !== hook.name),
|
||||
};
|
||||
});
|
||||
|
||||
return { previousHooks };
|
||||
},
|
||||
onError: (_error, _hookName, context) => {
|
||||
onError: (_error, _hook, context) => {
|
||||
if (context?.previousHooks) {
|
||||
queryClient.setQueryData(hooksKeys.lists(), context.previousHooks);
|
||||
}
|
||||
|
||||
@@ -4407,9 +4407,15 @@ export async function updateHookConfig(
|
||||
/**
|
||||
* Delete a hook
|
||||
*/
|
||||
export async function deleteHook(hookName: string): Promise<void> {
|
||||
return fetchApi<void>(`/api/hooks/delete/${encodeURIComponent(hookName)}`, {
|
||||
export async function deleteHook(params: {
|
||||
projectPath?: string;
|
||||
scope: 'global' | 'project';
|
||||
event: string;
|
||||
hookIndex: number;
|
||||
}): Promise<{ success: boolean }> {
|
||||
return fetchApi<{ success: boolean }>('/api/hooks', {
|
||||
method: 'DELETE',
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"skills": "Skills",
|
||||
"commands": "Commands",
|
||||
"memory": "Memory",
|
||||
"deepwiki": "DeepWiki",
|
||||
"prompts": "Prompt History",
|
||||
"settings": "Settings",
|
||||
"mcp": "MCP Servers",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"skills": "技能",
|
||||
"commands": "命令",
|
||||
"memory": "记忆",
|
||||
"deepwiki": "DeepWiki",
|
||||
"prompts": "提示历史",
|
||||
"settings": "设置",
|
||||
"mcp": "MCP 服务器",
|
||||
|
||||
@@ -177,6 +177,7 @@ export function DeepWikiPage() {
|
||||
symbols={symbols}
|
||||
isLoading={docLoading}
|
||||
error={docError}
|
||||
filePath={selectedFile ?? undefined}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -53,7 +53,7 @@ function isHookTriggerType(value: string): value is HookTriggerType {
|
||||
return ['SessionStart', 'UserPromptSubmit', 'PreToolUse', 'PostToolUse', 'Stop', 'Notification', 'SubagentStart', 'SubagentStop', 'PreCompact', 'SessionEnd', 'PostToolUseFailure', 'PermissionRequest'].includes(value);
|
||||
}
|
||||
|
||||
function toHookCardData(hook: { name: string; description?: string; enabled: boolean; trigger: string; matcher?: string; command?: string; script?: string }): HookCardData | null {
|
||||
function toHookCardData(hook: { name: string; description?: string; enabled: boolean; trigger: string; matcher?: string; command?: string; script?: string; scope?: 'global' | 'project'; index?: number }): HookCardData | null {
|
||||
if (!isHookTriggerType(hook.trigger)) {
|
||||
return null;
|
||||
}
|
||||
@@ -64,6 +64,8 @@ function toHookCardData(hook: { name: string; description?: string; enabled: boo
|
||||
trigger: hook.trigger,
|
||||
matcher: hook.matcher,
|
||||
command: hook.command || hook.script,
|
||||
scope: hook.scope,
|
||||
index: hook.index,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -200,8 +202,19 @@ export function HookManagerPage() {
|
||||
};
|
||||
|
||||
const handleDeleteClick = async (hookName: string) => {
|
||||
// Find the hook in filteredHooks to get scope and index
|
||||
const hook = filteredHooks.find(h => h.name === hookName);
|
||||
if (!hook) {
|
||||
console.error('Hook not found:', hookName);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await deleteHook(hookName);
|
||||
await deleteHook({
|
||||
name: hook.name,
|
||||
scope: hook.scope,
|
||||
trigger: hook.trigger,
|
||||
index: hook.index,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to delete hook:', error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user