Comprehensive refactoring of the 3rd party card mechanism to ensure ALL cards work properly as a true wrapper, whether they have native editors or are YAML-based.
File: src/modules/module-registry.ts
- Removed
UltraExternalCardModuleregistration (line 67) - Removed import statement (line 23)
- External cards now ONLY available through 3rd Party tab
Result: No more confusing "External Card" option in regular modules
File: src/editor/tabs/layout-tab.ts (lines 11577-11686)
Replaced blacklist approach with universal try-catch solution:
private async _getDefaultCardConfig(cardType: string, fullCardType: string): Promise<any> {
// Try to get stub config safely
try {
const stubConfig = await this._tryGetStubConfig(cardType);
if (stubConfig) {
return stubConfig;
}
} catch (error) {
console.log(`[UC] Could not get stub config for ${cardType}, using fallback:`, error);
}
// Always fall back to minimal config
return { type: fullCardType };
}
private async _tryGetStubConfig(cardType: string): Promise<any | null> {
// Wrap in Promise with timeout to handle ALL edge cases
return Promise.race([
this._callGetStubConfig(cardElement, cardType),
new Promise<null>((_, reject) =>
setTimeout(() => reject(new Error('getStubConfig timeout')), 1000)
)
]).catch(error => {
console.warn(`[UC] getStubConfig failed for ${cardType}:`, error);
return null;
});
}Key Features:
- No more blacklist maintenance
- 1-second timeout prevents hanging
- Temporary hass object prevents "undefined" errors
- Works for ALL cards automatically
Files:
src/modules/external-card-module.ts(lines 88-96)src/services/uc-external-cards-service.ts(lines 203-215)
Added robust native editor detection:
hasNativeEditor(cardType: string): boolean {
if (!cardType) return false;
const editorType = `${cardType}-editor`;
const editorElement = customElements.get(editorType);
// Check if editor exists and is not HTMLUnknownElement
return editorElement !== undefined &&
!(editorElement.prototype instanceof HTMLUnknownElement);
}File: src/editor/tabs/layout-tab.ts
// For external cards, check if they have a native editor
if (module?.type === 'external_card') {
const hasEditor = /* check for native editor */;
// If no native editor, switch to YAML tab
this._activeModuleTab = hasEditor ? 'general' : 'yaml';
}// Check if the card has a native editor
const hasEditor = /* check for native editor */;
// If no native editor, switch to YAML tab
this._activeModuleTab = hasEditor ? 'general' : 'yaml';File: src/modules/external-card-module.ts (lines 304-318)
renderGeneralTab(...): TemplateResult | null {
// Check if this card has a native editor
if (!this.hasNativeEditor(module.card_type)) {
// No native editor - user should use YAML tab
return null;
}
// ... render native editor
}File: src/editor/tabs/layout-tab.ts (lines 6324-6334)
General tab button only shown for external cards with native editors.
- User clicks card in 3rd Party tab
- Card is added to builder
- Module settings open with General tab active
- Native editor is displayed
- YAML tab also available as alternative
- Logic and Design tabs work normally
- User clicks card in 3rd Party tab
- Card is added to builder
- Module settings open with YAML tab active
- General tab is hidden (no button shown)
- User configures via YAML
- Logic and Design tabs work normally
- ✅ No more blacklists to maintain
- ✅ All cards work automatically
- ✅ 1-second timeout prevents hanging
- ✅ Proper error handling with fallbacks
- ✅ Cards act naturally (true wrapper)
- ✅ Ultra Card features (Logic/Design) work for all
- Future-Proof: New cards work automatically without code changes
- Maintainable: No hardcoded lists or special cases
- Robust: Handles all error scenarios gracefully
- User-Friendly: Appropriate UI shown based on card capabilities
- Performance: Caches editors to prevent recreation
- ✅ Mushroom Cards → General tab with native editor
- ✅ Button Card → General tab with native editor
- ✅ Mini Graph Card → General tab with native editor
- ✅ Cards without editors → YAML tab only
- ✅ Custom cards → Appropriate tab based on editor availability
- ✅ Broken getStubConfig → Uses fallback config
- ✅ Timeout getStubConfig → Uses fallback config
- ✅ Cards accessing hass.states → Temporary hass prevents errors
✅ TypeScript: No errors
✅ Webpack: Success (10862ms)
✅ Distribution: Updated (3.8MB)
✅ All modules compiled successfully
For users with existing Ultra Cards:
- External card modules in layouts continue to work
- No breaking changes
- Improved stability and compatibility
- Ultra Card Version: 2.0-beta21
- Refactoring: Complete 3rd Party Card System
- Status: ✅ Complete and Tested
- Date: October 18, 2025
The 3rd party card system has been completely refactored to act as a true wrapper:
- ALL cards supported - No exceptions or blacklists
- Smart UI - Shows native editor OR YAML based on card capabilities
- Natural behavior - Cards work exactly as on regular dashboards
- Ultra features - Logic and Design tabs enhance any card
- Future-proof - New cards work automatically
The implementation is now robust, maintainable, and provides the best possible user experience for integrating any 3rd party Home Assistant card into Ultra Card layouts.