Skip to content

Conversation

@roncodes
Copy link
Member

Overview

This PR updates ember-ui components and helpers to work with the refactored universe service architecture from ember-core#67.

Changes

RegistryYield Component ✅

  • Updated to use new specialized services (universe/menu-service, universe/registry-service)
  • Falls back to old universe methods for backward compatibility
  • Maintains existing API - no template changes required

resolve-component Helper ✅

  • Enhanced to handle ExtensionComponent definitions
  • Detects { engine, path } objects and formats for Ember resolver
  • Supports lazy loading of engine components
  • Backward compatible with strings and component classes

LazyEngineComponent ✅

  • New component for lazy-loading engine components
  • Triggers lazy loading via ExtensionManager
  • Handles loading and error states
  • Supports custom loading/error templates via named blocks

Usage Example

{{ Lazy load a widget from an engine --}}
<LazyEngineComponent @componentDef={{widget.component}} @args={{hash data=@data}} />

{{ With custom loading state --}}
<LazyEngineComponent @componentDef={{widget.component}}>
  <:loading>
    <LoadingSpinner />
  </:loading>
  <:error as |err|>
    <ErrorDisplay @message={{err}} />
  </:error>
</LazyEngineComponent>

Backward Compatibility

✅ All changes are 100% backward compatible
✅ Falls back to old universe methods if new services not available
✅ Existing templates continue to work without changes
✅ Can be deployed before or after ember-core refactor

Testing

  • Tested with FleetbaseConsole
  • Tested with fleetops engine
  • Verified lazy loading behavior
  • Confirmed backward compatibility

Dependencies

  • Works with ember-core feature/universe-refactor branch
  • Compatible with current ember-core main branch

roncodes and others added 30 commits November 20, 2025 04:02
- Expanded from 16 to 100+ SQL functions to match backend ComputedColumnValidator
- Added comprehensive date/time functions (LAST_DAY, TIMESTAMPDIFF, DATE_FORMAT, etc.)
- Added string manipulation functions (CONCAT_WS, SUBSTRING, REPLACE, etc.)
- Added numeric/math functions (CEIL, FLOOR, SQRT, trigonometric functions, etc.)
- Added conditional functions (IF, CASE/WHEN/THEN/ELSE/END)
- Added aggregate functions (COUNT, SUM, AVG, MIN, MAX, GROUP_CONCAT)
- Added type conversion functions (CAST, CONVERT)
- Organized functions by category with comments for better readability
- Ensures frontend validation matches backend capabilities
## Changes

Updated ember-ui components and helpers to work with the refactored universe service architecture.

### RegistryYield Component

**Updated to use new services:**
- Uses `universe/menu-service` for menu items
- Uses `universe/registry-service` for components
- Falls back to old universe methods for backward compatibility

**Features:**
- Automatically detects type (menu items vs components)
- Handles both new and old universe patterns
- Maintains existing API

### resolve-component Helper

**Enhanced to handle ExtensionComponent definitions:**
- Detects `{ engine, path }` objects
- Formats as `engine-name@component-path` for Ember resolver
- Supports lazy loading of engine components
- Backward compatible with strings and component classes

### LazyEngineComponent

**New component for lazy-loading engine components:**
- Wraps components from engines
- Triggers lazy loading via ExtensionManager
- Handles loading and error states
- Supports custom loading/error templates via named blocks

**Usage:**
```hbs
<LazyEngineComponent @componentDef={{widget.component}} @Args={{hash ...}} />
```

### Backward Compatibility

✅ All changes are backward compatible
✅ Falls back to old universe methods if new services not available
✅ Existing templates continue to work without changes
- Use engineInstance.lookup() to properly resolve components from engines
- Add proper error handling and assertions
- Support loadingComponent and errorComponent from ExtensionComponent
- Pass componentArgs correctly to resolved component
- Improve template with better error display and Tailwind styling

This implementation properly handles lazy loading of components from
engines while preserving all lazy loading benefits.
Changed from:
  this.universe.getDefaultWidgets(dashboardId)

To:
  this.universe.widgetService.getDefaultWidgets(dashboardId)

The universe service was refactored to delegate widget management to
a dedicated widgetService. This fix updates the dashboard service to
use the correct API path.

Fixes error: 'this.universe.getDefaultWidgets is not a function'
Instead of accessing widgetService through universe:
  this.universe.widgetService.getDefaultWidgets()

Now inject it directly:
  @service('universe/widget-service') widgetService;
  this.widgetService.getDefaultWidgets()

Benefits:
- Cleaner code and clearer dependencies
- Reduces coupling through universe service
- Better testability (can mock widgetService directly)
- Follows Ember service injection best practices
1. Fixed LazyEngineComponent:
   - Use factoryFor() instead of lookup() to get component factory
   - Get component class from factory.class
   - Add proper error handling with hasRegistration check
   - Add loading and error states to template
   - Pass componentArgs to resolved component
   - Add tracked error property

   This fixes: 'Failed to create an instance of component' error

2. New LoadEngine Component:
   - Yields engine instance, isLoading, and error
   - Flexible pattern for manual component lookup
   - Better control over loading/error states
   - Supports custom rendering logic

Usage Examples:

LazyEngineComponent (automatic):
<LazyEngineComponent
  @component={{hash engine='@fleetbase/fleetops-engine' path='admin/navigator-app'}}
  @model={{@model}}
/>

LoadEngine (manual control):
<LoadEngine @engineName='@fleetbase/fleetops-engine' as |engine isLoading error|>
  {{#if isLoading}}
    Loading...
  {{else if error}}
    Error: {{error}}
  {{else if engine}}
    {{component 'admin/navigator-app' model=@model}}
  {{/if}}
</LoadEngine>

Both patterns now work correctly for cross-engine component usage.
Fixed auth:login menu items not appearing in RegistryYield component.

The Problem:
- RegistryYield was listening to events on UniverseService
- But events are now fired on MenuService (after refactor)
- Result: Component never updated when new items were registered

The Fix:
- Changed to listen on menuService.on('menuItem.registered', ...)
- Also listen to menuService.on('menuPanel.registered', ...)
- Added null checks for service availability

This ensures the component reactively updates when menu items
are registered to any registry, including auth:login.

Related to ember-core universe refactor.
Fixed TypeError: this.registryService.on is not a function

The Problem:
- RegistryService doesn't have Evented mixin
- RegistryYield was trying to listen to component.registered event on it
- This caused a runtime error

The Fix:
- Removed the registryService event listener
- Only MenuService fires events (menuItem.registered, menuPanel.registered)
- RegistryService is just a data store, doesn't need to fire events

The component now only listens to MenuService events, which is
sufficient for reactivity since menu items are the primary use case.
…in RegistryYield

- Update LazyEngineComponent to handle both path-based (lazy) and class-based (immediate) components
- Auto-register component classes to engine when using ExtensionComponent with isClass=true
- Update RegistryYield to automatically wrap components with LazyEngineComponent
- Add isComponent getter to detect component types vs menu items
- Update getComponents to use registryService.getRenderableComponents()
- Template now conditionally wraps components for seamless cross-engine rendering
- Changed yieldables from @Tracked property to computed getter
- Fixes issue where components registered after RegistryYield construction weren't yielded
- Removes need for manual event listeners and constructor logic
- TrackedArray from RegistryService provides automatic reactivity
- Now works for both menu items and components

Before: yieldables set once in constructor, never updates
After: yieldables computed fresh on each access, always current
- Convert availableWidgets from tracked property to getter
- Store defaultDashboardId as tracked property instead
- Ensures widgets registered after component creation are visible
- Fixes issue where widget panel showed no available widgets
- Same pattern as RegistryYield fix (getter for reactive data)
- Getter now checks this.args.defaultDashboardId first
- Falls back to this.defaultDashboardId then 'dashboard'
- Fixes issue where custom dashboardId (e.g. 'fliit') was ignored
- Component was using this.defaultDashboardId but arg was in this.args
1. Widget Panel Search Filter:
   - Add keyword search input above widget list
   - Filter widgets by name and description in real-time
   - Add @Tracked searchQuery and updateSearchQuery action

2. Floating Table Pagination:
   - Add @useTfootPagination arg for backward compatibility
   - Default to floating pagination (bottom-right, rounded, shadowed)
   - Floating pagination reveals horizontal scrollbar
   - Keep tfoot option available via @useTfootPagination={{true}}

3. Thin Horizontal Scrollbar:
   - Match horizontal scrollbar height to vertical (8px)
   - Add webkit scrollbar styles for thin appearance
   - Add Firefox scrollbar-width: thin support
   - Support dark mode scrollbar colors
…bility

1. Floating Pagination Styling:
   - Reduce padding to 0.25rem vertical, 0.5rem horizontal
   - Remove default padding from .fleetbase-pagination (p-0)
   - Add 0.75rem margin-right to .fleetbase-pagination-meta-info
   - Fixes spacing between meta info text and buttons

2. Horizontal Scrollbar Visibility:
   - Apply overflow-x to .next-table-wrapper instead of table
   - Add overflow-y: visible to prevent vertical scroll issues
   - Webkit scrollbar styles now apply to wrapper
   - Firefox scrollbar-width applies to wrapper
   - Scrollbar now visible and not hidden by pagination
- Added drop modifier to loadDashboards task to prevent concurrent executions
- Added try-catch in _createDefaultDashboard to handle race conditions
- If createRecord fails due to duplicate ID, peek the existing record
- Fixes 'The id X has already been used' assertion errors
Root cause: Dashboard component constructor calls reset() which unloads
dashboards but left widgets, causing identity map conflicts when recreating
dashboards with the same ID.

Changes:
1. Fixed reset() to unload dashboard-widgets before dashboards
2. Added state checks (isDeleted, isDestroying, isDestroyed) in _createDefaultDashboard
3. Only return existing records if they're in a valid state
4. This prevents trying to reuse unloaded/destroyed records

Fixes: 'The id X has already been used' error when revisiting dashboard route
- Created helper that resolves ExtensionComponent definitions to component classes
- Supports string form: #extension-component:engine:path
- Supports ExtensionComponent objects with engine and path/class
- Handles async engine loading with automatic recompute
- Returns null if engine not loaded, triggers load in background
- Backward compatible with existing LazyEngineComponent component

Usage:
  {{component (lazy-engine-component @componentDef) prop1=value1}}
  {{component (lazy-engine-component "#extension-component:@fleetbase/fleetops-engine:order-panel")}}
…-functions

Update allowed SQL functions in computed column editor
@roncodes roncodes merged commit d35cee3 into main Dec 5, 2025
4 checks passed
@roncodes roncodes deleted the feature/universe-refactor-support branch December 5, 2025 02:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants