FleetbaseFleetbase
Resource ViewsMaking Your Views Extensible

Custom Views

Merge registered columns, actions, buttons and menu items into views you render yourself — a hand-built table, a page header, a dialog — and the context to pass to handlers.

Custom Views

If a view doesn't use the resource layouts, for example a <Table> with a header you built yourself, merge registered items in your controller. Each method below takes your built-in items and returns them with the registered ones placed in.

Columns and Row Actions

For a <Table> you render, merge columns and row actions together:

import { cached } from '@glimmer/tracking';

@cached get registeredColumns() {
    return this.shipmentActions.mergeRegisteredColumns(this.columns, { controller: this });
}
<Table @rows={{@model}} @columns={{this.registeredColumns}} />

Header Buttons and Menu Items

Merge with mergeHeaderButtons, and render with Layout::Resource::ActionButtons:

import { getOwner } from '@ember/application';
import lookupResourceView, { mergeHeaderButtons } from '@fleetbase/ember-ui/utils/resource-view';

get actionButtons() {
    const buttons = [{ id: 'refresh', icon: 'refresh', onClick: this.reload }];

    return mergeHeaderButtons(
        lookupResourceView(getOwner(this)),
        'acme:shipment:details',
        buttons,
        { resource: this.model, controller: this },
        { withMenu: true }
    );
}
<Layout::Section::Header @title={{@model.name}} @actionsWrapperClass="space-x-2">
    <Layout::Resource::ActionButtons @buttons={{this.actionButtons}} />
</Layout::Section::Header>

withMenu: true also merges the menu slot, for details views. Leave it out for a table header.

Any One Slot

mergeRegistered(surface, slot, items, context) on your action service merges a single slot:

get bulkActions() {
    return this.shipmentActions.mergeRegistered('table', 'bulk-actions', [{ id: 'bulk-delete', label: 'Delete selected', fn: this.bulkDelete }], {
        controller: this,
        getSelectedRows: () => this.table?.selectedRows ?? [],
    });
}

Layout::Resource::BulkActions renders a merged bulk actions list:

<Layout::Resource::BulkActions @actions={{this.bulkActions}} />

Dialogs

A details view in a modal can show registered buttons in its footer. The default modal renders actionButtons from its options:

this.modalsManager.show('modals/shipment-form', {
    title: 'Edit shipment',
    actionButtons: mergeHeaderButtons(this.resourceView, 'acme:shipment:details', [], { resource: shipment }, { withMenu: true }),
    // …
});

The Context to Pass

What you pass as the context is what handlers receive as ctx, alongside the registry's own keys (owner, registry, extension, resourceName, surface, slot):

ViewPass
Tablescontroller; table, as a getter, because the table is set up after the first render; getSelectedRows()
Detailsresource; controller or panel where you have them

Getters stay getters:

const view = this;
const context = {
    controller: this,
    get table() {
        return view.table;
    },
    getSelectedRows: () => view.table?.selectedRows ?? [],
};

Caching

Use @cached for merged lists a template reads more than once. Merging creates fresh copies each time, so anything users change on them, such as a column they hid, is lost on the next merge.

Custom Views | Fleetbase