mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-07 16:41:06 +08:00
feat: Add Role Analysis Reviewer Agent and validation template
- Introduced Role Analysis Reviewer Agent to validate role analysis outputs against templates and quality standards. - Created a detailed validation ruleset for the system-architect role, including mandatory and recommended sections. - Added JSON validation report structure for output. - Implemented execution command for validation process. test: Add UX tests for HookCard component - Created comprehensive tests for HookCard component, focusing on delete confirmation UX pattern. - Verified confirmation dialog appearance, deletion functionality, and button interactions. - Ensured proper handling of state updates and visual feedback for enabled/disabled status. test: Add UX tests for ThemeSelector component - Developed tests for ThemeSelector component, emphasizing delete confirmation UX pattern. - Validated confirmation dialog display, deletion actions, and toast notifications for undo functionality. - Ensured proper management of theme slots and state updates. feat: Implement useDebounce hook - Added useDebounce hook to delay expensive computations or API calls, enhancing performance. feat: Create System Architect Analysis Template - Developed a comprehensive template for system architect role analysis, covering required sections such as architecture overview, data model, state machine, error handling strategy, observability requirements, configuration model, and boundary scenarios. - Included examples and templates for each section to guide users in producing SPEC.md-level precision modeling.
This commit is contained in:
@@ -3,46 +3,93 @@
|
||||
// ========================================
|
||||
// Maps A2UI TextField component to shadcn/ui Input
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { Input } from '@/components/ui/Input';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { ComponentRenderer } from '../../core/A2UIComponentRegistry';
|
||||
import { resolveLiteralOrBinding } from '../A2UIRenderer';
|
||||
import type { TextFieldComponent } from '../../core/A2UITypes';
|
||||
|
||||
/**
|
||||
* A2UI TextField Component Renderer
|
||||
* Two-way binding via onChange updates to local state
|
||||
*/
|
||||
export const A2UITextField: ComponentRenderer = ({ component, onAction, resolveBinding }) => {
|
||||
const fieldComp = component as TextFieldComponent;
|
||||
const { TextField: fieldConfig } = fieldComp;
|
||||
|
||||
// Resolve initial value from binding or use empty string
|
||||
const initialValue = fieldConfig.value
|
||||
? String(resolveLiteralOrBinding(fieldConfig.value, resolveBinding) ?? '')
|
||||
: '';
|
||||
|
||||
// Local state for controlled input
|
||||
const [localValue, setLocalValue] = useState(initialValue);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [touched, setTouched] = useState(false);
|
||||
|
||||
const validate = useCallback((value: string) => {
|
||||
if (fieldConfig.required && !value) {
|
||||
return 'This field is required.';
|
||||
}
|
||||
if (fieldConfig.minLength && value.length < fieldConfig.minLength) {
|
||||
return `Must be at least ${fieldConfig.minLength} characters.`;
|
||||
}
|
||||
if (fieldConfig.maxLength && value.length > fieldConfig.maxLength) {
|
||||
return `Must be at most ${fieldConfig.maxLength} characters.`;
|
||||
}
|
||||
if (fieldConfig.pattern && !new RegExp(fieldConfig.pattern).test(value)) {
|
||||
return 'Invalid format.';
|
||||
}
|
||||
// `validator` is a placeholder for a more complex validation logic if needed
|
||||
if (fieldConfig.validator) {
|
||||
// Assuming validator is a regex string for simplicity
|
||||
try {
|
||||
if (!new RegExp(fieldConfig.validator).test(value)) {
|
||||
return 'Custom validation failed.';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Invalid validator regex:', fieldConfig.validator);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, [fieldConfig.required, fieldConfig.minLength, fieldConfig.maxLength, fieldConfig.pattern, fieldConfig.validator]);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalValue(initialValue);
|
||||
// Re-validate when initial value changes
|
||||
if (touched) {
|
||||
setError(validate(initialValue));
|
||||
}
|
||||
}, [initialValue, touched, validate]);
|
||||
|
||||
// Handle change with two-way binding
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = e.target.value;
|
||||
setLocalValue(newValue);
|
||||
|
||||
// Trigger action with new value
|
||||
setError(validate(newValue));
|
||||
|
||||
onAction(fieldConfig.onChange.actionId, {
|
||||
value: newValue,
|
||||
...(fieldConfig.onChange.parameters || {}),
|
||||
});
|
||||
}, [fieldConfig.onChange, onAction]);
|
||||
}, [fieldConfig.onChange, onAction, validate]);
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
setTouched(true);
|
||||
setError(validate(localValue));
|
||||
}, [localValue, validate]);
|
||||
|
||||
return (
|
||||
<Input
|
||||
type={fieldConfig.type || 'text'}
|
||||
value={localValue}
|
||||
onChange={handleChange}
|
||||
placeholder={fieldConfig.placeholder}
|
||||
/>
|
||||
<div>
|
||||
<Input
|
||||
type={fieldConfig.type || 'text'}
|
||||
value={localValue}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
placeholder={fieldConfig.placeholder}
|
||||
className={cn(touched && error && 'border-destructive')}
|
||||
maxLength={fieldConfig.maxLength}
|
||||
minLength={fieldConfig.minLength}
|
||||
required={fieldConfig.required}
|
||||
pattern={fieldConfig.pattern}
|
||||
/>
|
||||
{touched && error && (
|
||||
<p className="text-xs text-destructive mt-1">{error}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user