mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-06 16:31:12 +08:00
feat: 更新A2UIButton组件以支持A2UI快速操作和可用性检查;增强InjectionControlTab和QueueExecutionListView组件的错误处理和用户提示
This commit is contained in:
@@ -8,15 +8,20 @@ import { MessageSquare } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { useDialogStyleContext } from '@/contexts/DialogStyleContext';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useNotificationStore } from '@/stores';
|
||||
|
||||
interface A2UIButtonProps {
|
||||
className?: string;
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function A2UIButton({ className, compact = false }: A2UIButtonProps) {
|
||||
const { formatMessage } = useIntl();
|
||||
const { preferences } = useDialogStyleContext();
|
||||
const a2uiSurfaces = useNotificationStore((state) => state.a2uiSurfaces);
|
||||
const isA2UIAvailable = Object.keys(a2uiSurfaces).length > 0;
|
||||
|
||||
// Don't render if hidden in preferences
|
||||
if (!preferences.showA2UIButtonInToolbar) {
|
||||
@@ -24,21 +29,36 @@ export function A2UIButton({ className, compact = false }: A2UIButtonProps) {
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
// Trigger A2UI quick action - this would typically open a dialog
|
||||
// This would typically open the most relevant A2UI dialog
|
||||
// For now, we'll just log the action
|
||||
console.log('[A2UIButton] Quick action triggered');
|
||||
if (isA2UIAvailable) {
|
||||
console.log('[A2UIButton] Quick action triggered');
|
||||
// Example: find the first popup surface and handle it
|
||||
const firstPopupId = Object.keys(a2uiSurfaces).find(id => a2uiSurfaces[id].displayMode === 'popup');
|
||||
if(firstPopupId) {
|
||||
// In a real implementation, you might open a dialog here
|
||||
// using the surface data.
|
||||
console.log(`[A2UIButton] Would open dialog for surface: ${firstPopupId}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const buttonTitle = isA2UIAvailable
|
||||
? formatMessage({ id: 'navigation.toolbar.a2ui.quickAction', defaultMessage: 'A2UI Quick Action' })
|
||||
: formatMessage({ id: 'navigation.toolbar.a2ui.unavailable', defaultMessage: 'No A2UI action available' });
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="default"
|
||||
size={compact ? 'icon' : 'sm'}
|
||||
onClick={handleClick}
|
||||
disabled={!isA2UIAvailable}
|
||||
className={cn(
|
||||
'gap-2 bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
!isA2UIAvailable && 'bg-muted-foreground/30 hover:bg-muted-foreground/30',
|
||||
className
|
||||
)}
|
||||
title={formatMessage({ id: 'navigation.toolbar.a2ui.quickAction', defaultMessage: 'A2UI Quick Action' })}
|
||||
title={buttonTitle}
|
||||
>
|
||||
<MessageSquare className="h-4 w-4" />
|
||||
{!compact && (
|
||||
|
||||
@@ -922,12 +922,14 @@ export function InjectionControlTab({ className }: InjectionControlTabProps) {
|
||||
step={500}
|
||||
value={formData.maxLength}
|
||||
onChange={(e) => handleFieldChange('maxLength', Number(e.target.value))}
|
||||
className={cn(maxLengthError && 'border-destructive')}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-sm text-muted-foreground whitespace-nowrap">
|
||||
(~{Math.ceil(formData.maxLength / 80)} {formatMessage({ id: 'specs.injection.lines', defaultMessage: 'lines' })})
|
||||
</span>
|
||||
</div>
|
||||
{maxLengthError && <p className="text-xs text-destructive mt-1">{maxLengthError}</p>}
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{formatMessage({
|
||||
id: 'specs.injection.maxLengthHelp',
|
||||
@@ -981,12 +983,14 @@ export function InjectionControlTab({ className }: InjectionControlTabProps) {
|
||||
step={500}
|
||||
value={formData.warnThreshold}
|
||||
onChange={(e) => handleFieldChange('warnThreshold', Number(e.target.value))}
|
||||
className={cn(warnThresholdError && 'border-destructive')}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-sm text-muted-foreground whitespace-nowrap">
|
||||
(~{Math.ceil(formData.warnThreshold / 80)} {formatMessage({ id: 'specs.injection.lines', defaultMessage: 'lines' })})
|
||||
</span>
|
||||
</div>
|
||||
{warnThresholdError && <p className="text-xs text-destructive mt-1">{warnThresholdError}</p>}
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{formatMessage({
|
||||
id: 'specs.injection.warnThresholdHelp',
|
||||
@@ -1024,7 +1028,7 @@ export function InjectionControlTab({ className }: InjectionControlTabProps) {
|
||||
>
|
||||
{formatMessage({ id: 'common.actions.reset', defaultMessage: 'Reset' })}
|
||||
</Button>
|
||||
<Button onClick={handleSave} disabled={!hasChanges || isSaving}>
|
||||
<Button onClick={handleSave} disabled={!hasChanges || isSaving || !!maxLengthError || !!warnThresholdError}>
|
||||
{isSaving ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { ClipboardList } from 'lucide-react';
|
||||
import { Inbox } from 'lucide-react';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useQueueExecutionStore } from '@/stores/queueExecutionStore';
|
||||
import { useTerminalPanelStore } from '@/stores/terminalPanelStore';
|
||||
@@ -65,17 +66,31 @@ function QueueExecutionItem({
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ========== Empty State ==========
|
||||
|
||||
function QueueEmptyState() {
|
||||
const { formatMessage } = useIntl();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleCreateQueue = () => {
|
||||
navigate(ROUTES.ORCHESTRATOR);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex-1 flex items-center justify-center text-muted-foreground">
|
||||
<div className="text-center">
|
||||
<ClipboardList className="h-12 w-12 mx-auto mb-4 opacity-50" />
|
||||
<p className="text-sm">{formatMessage({ id: 'home.terminalPanel.queueView.emptyTitle' })}</p>
|
||||
<p className="text-xs mt-1">{formatMessage({ id: 'home.terminalPanel.queueView.emptyDesc' })}</p>
|
||||
<div className="text-center p-4">
|
||||
<Inbox className="h-12 w-12 mx-auto mb-4 opacity-40" />
|
||||
<p className="text-sm font-medium text-foreground">
|
||||
{formatMessage({ id: 'home.terminalPanel.queueView.emptyTitleV2', defaultMessage: 'Execution queue is empty' })}
|
||||
</p>
|
||||
<p className="text-xs mt-1 mb-4">
|
||||
{formatMessage({ id: 'home.terminalPanel.queueView.emptyDescV2', defaultMessage: 'Create an execution queue to run tasks in sequence.' })}
|
||||
</p>
|
||||
<Button size="sm" onClick={handleCreateQueue}>
|
||||
{formatMessage({ id: 'home.terminalPanel.queueView.createQueue', defaultMessage: 'Create Queue' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user