FleetbaseFleetbase

Templates & Components

Build engine templates and Glimmer components using @fleetbase/ember-ui — layout primitives, common widgets, and how to render extension components inside other engines.

Templates & Components

Engine templates use standard Handlebars + Ember. The console ships a large component library — @fleetbase/ember-ui — that gives you matching chrome (layouts, headers, tables, modals, form inputs) without re-implementing styles.

Templates

Engine templates live under addon/templates/, mirroring the route map:

addon/
├── routes.js                                 # this.route('orders', { ... })
├── routes/
│   └── orders.js
├── controllers/
│   └── orders.js
└── templates/
    ├── application.hbs                       # outermost layout for the engine
    └── orders.hbs                            # rendered for the orders route

The engine's application.hbs is your top-level layout — wrap content in the standard <Layout::Section> chrome so it sits correctly inside the console:

{{!-- addon/templates/application.hbs --}}
<Layout::Container>
    <Layout::Sidebar />
    <Layout::Section>
        {{outlet}}
    </Layout::Section>
</Layout::Container>

Glimmer Components

Components live under addon/components/. Use Octane (@glimmer/component):

// addon/components/order-summary.js
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';

export default class OrderSummaryComponent extends Component {
    @service fetch;
    @service notifications;

    @tracked isLoading = false;

    @action
    async refresh() {
        this.isLoading = true;
        try {
            await this.fetch.get(`my-extension/v1/orders/${this.args.order.id}/refresh`);
            this.notifications.success('Refreshed');
        } finally {
            this.isLoading = false;
        }
    }
}
{{!-- addon/components/order-summary.hbs --}}
<div class="rounded-md border p-4">
    <h3 class="font-semibold">{{@order.public_id}}</h3>
    <Button @text="Refresh" @icon="rotate" @isLoading={{this.isLoading}} @onClick={{this.refresh}} />
</div>

Using @fleetbase/ember-ui

@fleetbase/ember-ui is already on your engine's resolver path — components are available globally without imports. The library covers the platform's design system; reach for it before building chrome from scratch.

Full component reference: Fleetbase UI docs. Each component below links to its dedicated page with props, slots, examples, and edge cases.

Layout primitives

ComponentPurposeDocs
<Layout::Container>Outer wrapper with sidebar + section gridLayout overview
<Layout::Sidebar>Collapsible engine sidebarLayout overview
<Layout::Section>Main content column with header/body slotsLayout overview
<Layout::Section::Header @title="…" />Page header barLayout overview
<Layout::Section::Body>Scrollable body containerLayout overview
<ContentPanel @title @open>Collapsible labeled sectionContent Panel
<Drawer>Slide-out side panelDrawer
<Overlay>Backdrop + portal targetOverlay
<Spacer @height>Vertical spacingSpacer

Actions

ComponentPurposeDocs
<Button @text @icon @type @onClick @isLoading />Variants: primary, magic, danger, etc.Button
<ClickToCopy @value />Copy-on-click affordanceClick to Copy
<ClickToReveal />Reveal hidden content (secrets, tokens)Click to Reveal

Display

ComponentPurposeDocs
<Spinner />Loading indicatorSpinner
<Badge @text @type />Status badgesBadge
<Pill @text />Compact label chipPill
<Table @data @columns />Sortable, paginatable data tableTable
<Timeline />Vertical event timelineTimeline
<ActivityLog />Activity feedActivity Log
<ProgressBar />Progress indicatorProgress Bar

Form Inputs

ComponentPurposeDocs
<Select @options @onChange />Styled selectSelect
<MultiSelect />Multiple selection with chipsMulti Select
<ComboBox />Searchable dropdownCombo Box
<Checkbox /> / <Toggle />Boolean inputsCheckbox, Toggle
<DatePicker /> / <DateTimeInput />Date / date-time pickersDate Picker
<MoneyInput />Currency-aware amount inputMoney Input
<UnitInput />Number with unit selectorUnit Input
<PhoneInput />International phone inputPhone Input
<FileUpload />Drag-and-drop file uploadFile Upload
<CoordinatesInput />Lat/lng + mapCoordinates Input
<ModelSelect />Searchable Ember Data record pickerModel Select
<InputGroup />Label + input + help text wrapperInput Group

For complete documentation — including extending components, slot content, and accessibility notes — see the Fleetbase UI documentation.

Cross-engine Components

When another extension wants to render a component from your engine — say, on the Fleet-Ops order details page — the boundary crosses engines. You don't pass component names directly; you pass an ExtensionComponent, which the host resolves lazily.

import { ExtensionComponent } from '@fleetbase/ember-core/contracts';

const ref = new ExtensionComponent(
    '@fleetbase/storefront-engine',
    'storefront-order-summary' // resolves to addon/components/storefront-order-summary.{js,hbs}
);

The receiving registry (e.g. 'fleet-ops:component:order:details') renders ref via <LazyEngineComponent>, which loads the source engine on demand if it isn't already booted.

{{!-- inside the host engine --}}
<LazyEngineComponent
    @component={{this.extensionComponent}}
    @params={{this.componentArgs}}
/>

You don't usually invoke <LazyEngineComponent> yourself — the Registry Service and Virtual Routes wire it for you.

Tailwind & Styling

The console uses Tailwind utility classes and a small set of design tokens. Most ember-ui components accept utility class strings via @class or pass-through HTML attributes (class="…"). For one-off styles, scope them to your engine via component-tree CSS or Tailwind utilities.

If you need engine-scoped global CSS, drop a stylesheet under addon/styles/ember-cli-build.js will pick it up.

Services Available in Components

These host services are wired into your engine via @fleetbase/ember-core/exports and can be injected into any component. Detailed reference: Ember Services.

ServiceUse for
fetchAuthenticated HTTP requests — pass { namespace } to hit your extension's API
storeEmber Data StorefindRecord, query, etc.
notificationsToast notifications (success, error, info, warning)
currentUserLogged-in user
sessionAuth session, including session.data.authenticated
modalsManagerImperative modal API
themeSet body classes, toggle dark mode
intli18n / translations
abilitiesRole-based permission checks (ember-can)
crudGeneric CRUD action helpers
eventsApp-wide event bus
socketReal-time pub/sub
appCacheBrowser-storage-backed cache
universeThe universe service itself + sub-services
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';

export default class extends Component {
    @service fetch;
    @service notifications;
    @service abilities;
}

See Also

Source

FileDescription
packages/ember-ui/addon/componentsAll shared UI components (source)
packages/ember-core/addon/exports/services.jsServices available to engines
Templates & Components | Fleetbase