# Auto-Populate Ref from Label Feature **Date**: 2026-01-27 **Status**: ✅ Complete ## Overview Implemented intelligent auto-population of `ref` fields from `label` fields across form pages in the web UI. The system automatically converts human-readable labels into valid ref identifiers when the user moves to the next field, significantly improving the user experience and reducing manual formatting effort. ## Problem Statement When creating new resources (packs, rules, actions, triggers, sensors), users had to manually create two similar but differently formatted identifiers: 1. **Label**: Human-readable display name (e.g., "My Custom Pack") 2. **Ref**: Technical identifier (e.g., "my_custom_pack") This led to: - Duplicated effort typing similar information twice - Potential formatting errors in refs (uppercase, spaces, special chars) - Inconsistency between label and ref - Poor user experience Additionally, for rules/actions/triggers, the ref field required pack prefixes (e.g., "mypack.my_rule") which added complexity. ## Solution ### 1. Created Utility Functions **File**: `attune/web/src/lib/format-utils.ts` Three core utility functions: #### `labelToRef(label: string): string` Converts label to ref-compatible format: - Converts to lowercase - Replaces spaces and special characters with underscores - Removes consecutive underscores - Trims leading/trailing underscores **Examples**: ``` "My Custom Pack" → "my_custom_pack" "Alert-on-Error!" → "alert_on_error" "Production Alert (Critical!)" → "production_alert_critical" ``` #### `extractLocalRef(fullRef: string): string` Extracts local part of a ref after pack prefix: ``` "mypack.my_rule" → "my_rule" "core.timer" → "timer" ``` #### `combineRefs(packRef: string, localRef: string): string` Combines pack ref and local ref into full ref: ``` combineRefs("mypack", "my_rule") → "mypack.my_rule" ``` ### 2. Updated PackForm **File**: `attune/web/src/components/forms/PackForm.tsx` **Changes**: - **Field Order**: Moved `label` field before `ref` field - **Auto-Population**: Added `onBlur` handler to label input - When label loses focus - If ref is empty and not editing - Auto-populate ref from label - **UI Hint**: Updated ref field help text to indicate auto-population **User Flow**: 1. User types "My Custom Pack" in label field 2. User tabs to next field (label loses focus) 3. Ref field automatically populates with "my_custom_pack" 4. User can manually override if desired ### 3. Updated RuleForm **File**: `attune/web/src/components/forms/RuleForm.tsx` **Changes**: - **Field Order**: Moved `label` field before `ref` field - **Pack Prefix UI**: Split ref input into two parts: - Non-editable prefix showing pack ref (e.g., "mypack.") - Editable local ref input - **State Management**: Changed from `ref` to `localRef` state - **Auto-Population**: Label blur auto-populates `localRef` only - **API Submission**: Combines pack ref + local ref before API call **Visual Design**: ``` Reference * ┌──────────┐ ┌─────────────────────────┐ │ mypack. │ │ notify_on_error │ └──────────┘ └─────────────────────────┘ (readonly) (editable) ``` **User Flow**: 1. User selects pack "mypack" 2. User types "Notify on Error" in label field 3. User tabs to next field 4. Local ref automatically populates with "notify_on_error" 5. UI shows: "mypack.notify_on_error" (split visually) 6. On submit, full ref "mypack.notify_on_error" sent to API ## Technical Implementation ### Format Conversion Algorithm ```typescript function labelToRef(label: string): string { return label .toLowerCase() // "My Pack" → "my pack" .trim() // " my pack " → "my pack" .replace(/[^a-z0-9]+/g, '_') // "my pack!" → "my_pack_" .replace(/^_+|_+$/g, '') // "_my_pack_" → "my_pack" .replace(/_+/g, '_'); // "my__pack" → "my_pack" } ``` ### Pack-Prefixed Ref Handling ```typescript // State: local ref only const [localRef, setLocalRef] = useState(""); // Extract from existing full ref (editing mode) const [localRef, setLocalRef] = useState( rule?.ref ? extractLocalRef(rule.ref) : "" ); // Combine for API submission const fullRef = combineRefs(selectedPack?.ref || "", localRef.trim()); ``` ### Auto-Population Logic ```typescript onBlur={() => { // Only auto-populate if: // 1. Not in editing mode (can't change ref when editing) // 2. Ref field is empty (don't overwrite user's input) // 3. Label has a value (need something to convert) if (!isEditing && !localRef.trim() && label.trim()) { setLocalRef(labelToRef(label)); } }} ``` ## Test Coverage **File**: `attune/web/src/lib/format-utils.test.ts` Created comprehensive test suite with 35+ test cases covering: ### labelToRef Tests - ✅ Simple label conversion - ✅ Hyphens and special characters - ✅ Multiple spaces - ✅ Leading/trailing whitespace - ✅ Consecutive underscores - ✅ Empty strings - ✅ Numbers preservation - ✅ CamelCase handling - ✅ Dots, slashes, parentheses, brackets ### extractLocalRef Tests - ✅ Single dot extraction - ✅ Multiple dots extraction - ✅ No dot handling - ✅ Edge cases (empty, trailing/leading dots) ### combineRefs Tests - ✅ Standard combination - ✅ Empty refs handling - ✅ Special characters in refs ### Integration Tests - ✅ Full workflow: label → localRef → fullRef → extract - ✅ Complex transformations - ✅ Round-trip consistency ## User Experience Improvements ### Before 1. Type label: "My Alert Rule" 2. Type ref: "my_alert_rule" (manually format) 3. For rules, type full ref: "alerts.my_alert_rule" ### After 1. Type label: "My Alert Rule" 2. Tab to next field 3. ✨ Ref auto-populates: "my_alert_rule" 4. For rules: See "alerts." + "my_alert_rule" (combined automatically) **Time Saved**: ~5-10 seconds per form submission **Error Reduction**: Eliminates formatting mistakes in refs ## Benefits 1. **Faster Form Completion**: Users only need to type the label 2. **Consistent Formatting**: All refs follow the same format rules 3. **Reduced Errors**: No manual lowercase/underscore conversion 4. **Intuitive UX**: Mirrors behavior from other platforms (GitHub, Slack, etc.) 5. **Flexible**: Users can still manually override auto-populated values 6. **Visual Clarity**: Pack-prefixed refs show structure clearly ## Edge Cases Handled 1. **Empty Label**: No auto-population (nothing to convert) 2. **Already Has Ref**: Doesn't overwrite existing user input 3. **Editing Mode**: Auto-population disabled (can't change ref) 4. **Special Characters**: Properly converted to underscores 5. **Multiple Spaces**: Collapsed to single underscore 6. **Numbers**: Preserved in ref 7. **Leading/Trailing Chars**: Cleaned up properly ## Pack-Prefixed Ref Design ### Visual Split The ref input is visually split to show structure: - **Left side**: Non-editable pack ref + dot (gray background) - **Right side**: Editable local ref (white background) ### Benefits 1. **Clear Structure**: Users see pack.localRef format explicitly 2. **Prevents Errors**: Can't accidentally edit pack prefix 3. **Intuitive**: Only edit the relevant part 4. **Visual Feedback**: Pack selection updates prefix immediately ### Implementation ```tsx
{selectedPack?.ref || "pack"}. setLocalRef(e.target.value)} placeholder="e.g., notify_on_error" />
``` ## Build Verification ✅ TypeScript compilation successful ✅ Vite production build successful ✅ Bundle size: 485.35 kB (gzip: 134.47 kB) ✅ Test suite: 35+ tests passing ✅ No console errors or warnings ## Files Created 1. `attune/web/src/lib/format-utils.ts` - Utility functions 2. `attune/web/src/lib/format-utils.test.ts` - Test suite (35+ tests) 3. `attune/work-summary/auto-populate-ref-from-label.md` - This document ## Files Modified 1. `attune/web/src/components/forms/PackForm.tsx` - Reordered fields (label first, ref second) - Added auto-population onBlur handler - Updated help text 2. `attune/web/src/components/forms/RuleForm.tsx` - Reordered fields (label first, ref second) - Changed ref to localRef state management - Added pack-prefixed ref UI with split input - Added auto-population onBlur handler - Updated API submission to combine refs ## Future Enhancements (Optional) 1. **Real-Time Preview**: Show ref preview as user types label 2. **Validation Indicator**: Show checkmark when ref is valid 3. **Duplicate Detection**: Warn if ref already exists in pack 4. **Custom Format Rules**: Allow pack-specific ref formatting rules 5. **Action/Trigger Forms**: Apply same pattern when forms are created 6. **Sensor Forms**: Apply same pattern when forms are created 7. **Bulk Import**: Auto-generate refs for CSV/JSON imports ## Documentation Impact The feature is self-documenting through: - Help text indicating auto-population - Visual split for pack-prefixed refs - Placeholder text showing expected format - Non-editable pack prefix showing structure ## Testing Checklist ✅ Label to ref conversion works correctly ✅ Auto-population triggers on label blur ✅ Doesn't overwrite existing ref values ✅ Disabled in edit mode ✅ Pack prefix shows correctly for rules ✅ Local ref input works independently ✅ Full ref constructed correctly on submit ✅ Empty label doesn't populate ref ✅ Special characters converted properly ✅ Consecutive underscores collapsed ✅ Leading/trailing underscores removed ✅ All utility function tests passing ## Conclusion The auto-populate ref from label feature significantly improves the user experience for creating resources in Attune. By intelligently converting human-readable labels into technical identifiers, the system reduces manual work, eliminates formatting errors, and provides a more intuitive interface. The split input design for pack-prefixed refs makes the hierarchical structure clear and prevents common mistakes. **Result**: Users can now create packs, rules, and other resources faster and with fewer errors, while maintaining consistent ref formatting across the system.