mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-29 06:32:28 +00:00
perf(web): switch remaining components to deep lucide imports, extract ProviderConfigCard
- BackendRepoSelector, EmbeddingStatus, Header, MermaidDiagram, QueryFAB, RightPanel, ToolCallCard, WebGPUFallbackDialog: switch from lucide-react barrel imports to @/lib/lucide-icons deep imports - MermaidDiagram: lazy-load ProcessFlowModal via React.lazy - Extract ProviderConfigCard from SettingsPanel for cleaner separation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ab3b876f66
commit
32be69c8ee
9 changed files with 135 additions and 15 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { Server, ArrowRight } from 'lucide-react';
|
||||
import { Server, ArrowRight } from '@/lib/lucide-icons';
|
||||
import { BackendRepo } from '../services/backend';
|
||||
|
||||
interface BackendRepoSelectorProps {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Brain, Loader2, Check, AlertCircle, Zap, FlaskConical } from 'lucide-react';
|
||||
import { Brain, Loader2, Check, AlertCircle, Zap, FlaskConical } from '@/lib/lucide-icons';
|
||||
import { useAppState } from '../hooks/useAppState';
|
||||
import { useState } from 'react';
|
||||
import { WebGPUFallbackDialog } from './WebGPUFallbackDialog';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Search, Settings, HelpCircle, Sparkles, Github, Star, ChevronDown } from 'lucide-react';
|
||||
import { Search, Settings, HelpCircle, Sparkles, Github, Star, ChevronDown } from '@/lib/lucide-icons';
|
||||
import { useAppState } from '../hooks/useAppState';
|
||||
import type { RepoSummary } from '../services/server-connection';
|
||||
import { useState, useMemo, useRef, useEffect, useCallback } from 'react';
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Suspense, useEffect, useRef, useState, lazy } from 'react';
|
||||
import mermaid from 'mermaid';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { AlertTriangle, Maximize2 } from 'lucide-react';
|
||||
import { ProcessFlowModal } from './ProcessFlowModal';
|
||||
import { AlertTriangle, Maximize2 } from '@/lib/lucide-icons';
|
||||
import type { ProcessData } from '../lib/mermaid-generator';
|
||||
|
||||
const ProcessFlowModal = lazy(() =>
|
||||
import('./ProcessFlowModal').then((m) => ({ default: m.ProcessFlowModal })),
|
||||
);
|
||||
|
||||
// Initialize mermaid with cyan theme matching ProcessFlowModal
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
|
|
@ -68,7 +71,8 @@ export const MermaidDiagram = ({ code }: MermaidDiagramProps) => {
|
|||
|
||||
// Render the diagram
|
||||
const { svg: renderedSvg } = await mermaid.render(id, code.trim());
|
||||
setSvg(renderedSvg);
|
||||
const sanitizedSvg = DOMPurify.sanitize(renderedSvg, { USE_PROFILES: { svg: true, svgFilters: true } });
|
||||
setSvg(sanitizedSvg);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
// Silent catch for streaming:
|
||||
|
|
@ -148,10 +152,16 @@ export const MermaidDiagram = ({ code }: MermaidDiagramProps) => {
|
|||
|
||||
{/* Use ProcessFlowModal for expansion */}
|
||||
{showModal && processData && (
|
||||
<ProcessFlowModal
|
||||
process={processData}
|
||||
onClose={() => setShowModal(false)}
|
||||
/>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="p-4 text-sm text-text-muted">Loading diagram…</div>
|
||||
}
|
||||
>
|
||||
<ProcessFlowModal
|
||||
process={processData}
|
||||
onClose={() => setShowModal(false)}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useRef, useEffect, useCallback } from 'react';
|
||||
import { Terminal, Play, X, ChevronDown, ChevronUp, Loader2, Sparkles, Table } from 'lucide-react';
|
||||
import { Terminal, Play, X, ChevronDown, ChevronUp, Loader2, Sparkles, Table } from '@/lib/lucide-icons';
|
||||
import { useAppState } from '../hooks/useAppState';
|
||||
|
||||
const EXAMPLE_QUERIES = [
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useState, useRef, useEffect, useCallback } from 'react';
|
|||
import {
|
||||
Send, Square, Sparkles, User,
|
||||
PanelRightClose, Loader2, AlertTriangle, GitBranch
|
||||
} from 'lucide-react';
|
||||
} from '@/lib/lucide-icons';
|
||||
import { useAppState } from '../hooks/useAppState';
|
||||
import { ToolCallCard } from './ToolCallCard';
|
||||
import { isProviderConfigured } from '../core/llm/settings-service';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
import { ChevronDown, ChevronRight, Sparkles, Check, Loader2, AlertCircle } from 'lucide-react';
|
||||
import { ChevronDown, ChevronRight, Sparkles, Check, Loader2, AlertCircle } from '@/lib/lucide-icons';
|
||||
import type { ToolCallInfo } from '../core/llm/types';
|
||||
|
||||
interface ToolCallCardProps {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { X, Snail, Rocket, SkipForward } from 'lucide-react';
|
||||
import { X, Snail, Rocket, SkipForward } from '@/lib/lucide-icons';
|
||||
|
||||
interface WebGPUFallbackDialogProps {
|
||||
isOpen: boolean;
|
||||
|
|
|
|||
110
gitnexus-web/src/components/settings/ProviderConfigCard.tsx
Normal file
110
gitnexus-web/src/components/settings/ProviderConfigCard.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { Eye, EyeOff, Key } from '@/lib/lucide-icons';
|
||||
|
||||
type ApiKeyField = {
|
||||
value: string;
|
||||
placeholder: string;
|
||||
helperText?: string;
|
||||
helperLink?: string;
|
||||
helperLinkLabel?: string;
|
||||
isVisible: boolean;
|
||||
onChange: (value: string) => void;
|
||||
onToggleVisibility: () => void;
|
||||
};
|
||||
|
||||
type ModelField = {
|
||||
value: string;
|
||||
placeholder: string;
|
||||
label?: string;
|
||||
helperText?: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
interface ProviderConfigCardProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
apiKey?: ApiKeyField;
|
||||
model?: ModelField;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const ProviderConfigCard = ({
|
||||
title,
|
||||
description,
|
||||
apiKey,
|
||||
model,
|
||||
children,
|
||||
}: ProviderConfigCardProps) => {
|
||||
return (
|
||||
<div className="space-y-4 animate-fade-in">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-text-primary">{title}</h3>
|
||||
{description ? (
|
||||
<p className="text-xs text-text-muted">{description}</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{apiKey && (
|
||||
<div className="space-y-2">
|
||||
<label className="flex items-center gap-2 text-sm font-medium text-text-secondary">
|
||||
<Key className="w-4 h-4" />
|
||||
API Key
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={apiKey.isVisible ? 'text' : 'password'}
|
||||
value={apiKey.value}
|
||||
onChange={e => apiKey.onChange(e.target.value)}
|
||||
placeholder={apiKey.placeholder}
|
||||
className="w-full px-4 py-3 pr-12 bg-elevated border border-border-subtle rounded-xl text-text-primary placeholder:text-text-muted focus:border-accent focus:ring-2 focus:ring-accent/20 outline-none transition-all"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={apiKey.onToggleVisibility}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 p-1 text-text-muted hover:text-text-primary transition-colors"
|
||||
>
|
||||
{apiKey.isVisible ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
{apiKey.helperText && (
|
||||
<p className="text-xs text-text-muted">
|
||||
{apiKey.helperText}{' '}
|
||||
{apiKey.helperLink ? (
|
||||
<a
|
||||
href={apiKey.helperLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-accent hover:underline"
|
||||
>
|
||||
{apiKey.helperLinkLabel ?? 'Learn more'}
|
||||
</a>
|
||||
) : null}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{model && (
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-text-secondary">
|
||||
{model.label ?? 'Model'}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={model.value}
|
||||
onChange={e => model.onChange(e.target.value)}
|
||||
placeholder={model.placeholder}
|
||||
className="w-full px-4 py-3 bg-elevated border border-border-subtle rounded-xl text-text-primary placeholder:text-text-muted focus:border-accent focus:ring-2 focus:ring-accent/20 outline-none transition-all font-mono text-sm"
|
||||
/>
|
||||
{model.helperText ? (
|
||||
<p className="text-xs text-text-muted">{model.helperText}</p>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue