Reference for all Ember addons used in A3 — ember-simple-auth, ember-can, ember-power-select, ember-basic-dropdown, ember-file-upload, ember-keyboard, ember-sortable, ember-shepherd, ember-shiki, and more
From a3-pluginnpx claudepluginhub trusted-american/marketplace --plugin a3-pluginThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Implements structured self-debugging workflow for AI agent failures: capture errors, diagnose patterns like loops or context overflow, apply contained recoveries, and generate introspection reports.
Authentication/session management. See auth-permissions skill for details.
Authorization/abilities. See auth-permissions skill for details.
Async task management. See ember-concurrency skill for details.
Internationalization. See ember-intl skill for details.
Advanced select/dropdown component:
import PowerSelect from 'ember-power-select/components/power-select';
<template>
<PowerSelect
@options={{this.carrierOptions}}
@selected={{@model.carrier}}
@onChange={{fn (mut @model.carrier)}}
@searchEnabled={{true}}
@searchField="name"
@placeholder={{t "fields.selectCarrier"}}
as |carrier|
>
{{carrier.name}}
</PowerSelect>
</template>
import PowerSelectMultiple from 'ember-power-select/components/power-select-multiple';
<template>
<PowerSelectMultiple
@options={{this.tagOptions}}
@selected={{@model.tags}}
@onChange={{fn (mut @model.tags)}}
as |tag|
>
{{tag.name}}
</PowerSelectMultiple>
</template>
Docs: https://ember-power-select.com/
Low-level dropdown primitive (used by ember-power-select internally):
import BasicDropdown from 'ember-basic-dropdown/components/basic-dropdown';
<template>
<BasicDropdown as |dd|>
<dd.Trigger>
<button>Open Menu</button>
</dd.Trigger>
<dd.Content>
<ul class="dropdown-menu show">
<li><button {{on "click" (fn this.select "option1")}}>Option 1</button></li>
<li><button {{on "click" (fn this.select "option2")}}>Option 2</button></li>
</ul>
</dd.Content>
</BasicDropdown>
</template>
Docs: https://ember-basic-dropdown.com/
File upload with drag-and-drop:
import FileUpload from 'ember-file-upload/components/file-upload';
import FileDropzone from 'ember-file-upload/components/file-dropzone';
<template>
<FileDropzone @name="documents" as |dropzone|>
{{#if dropzone.active}}
<div class="dropzone-active">Drop files here</div>
{{/if}}
<FileUpload
@name="documents"
@accept="application/pdf,image/*"
@onFileAdded={{this.handleFileAdded}}
>
<button class="btn btn-outline-primary">Upload File</button>
</FileUpload>
</FileDropzone>
</template>
Docs: https://ember-file-upload.pages.dev/
Keyboard shortcut handling:
import { onKey } from 'ember-keyboard';
export default class MyComponent extends Component {
@onKey('ctrl+s')
save() {
this.saveTask.perform();
}
@onKey('Escape')
close() {
this.args.onClose?.();
}
}
Docs: https://adopted-ember-addons.github.io/ember-keyboard/
Drag-and-drop reordering:
import SortableGroup from 'ember-sortable/components/sortable-group';
import SortableItem from 'ember-sortable/components/sortable-item';
<template>
<SortableGroup @onChange={{this.reorder}} as |group|>
{{#each @items as |item|}}
<SortableItem @model={{item}} @group={{group}}>
<div class="sortable-item">{{item.name}}</div>
</SortableItem>
{{/each}}
</SortableGroup>
</template>
Docs: https://github.com/adopted-ember-addons/ember-sortable
User onboarding tours:
import { service } from '@ember/service';
import type TourService from 'a3/services/tour';
export default class MyComponent extends Component {
@service declare tour: TourService;
@action
startTour() {
this.tour.addSteps([
{
id: 'step-1',
text: 'Welcome! This is the enrollment list.',
attachTo: { element: '[data-test-enrollment-list]', on: 'bottom' },
},
{
id: 'step-2',
text: 'Click here to create a new enrollment.',
attachTo: { element: '[data-test-new-button]', on: 'bottom' },
},
]);
this.tour.start();
}
}
Docs: https://github.com/rwwagner90/ember-shepherd
Page title management:
import { pageTitle } from 'ember-page-title';
<template>
{{pageTitle "Enrollments"}}
{{! Sets document.title to "Enrollments | A3" }}
</template>
Breadcrumb navigation:
// In route
export default class MyRoute extends Route {
breadcrumb = { title: 'Enrollments' };
}
Toast notification messages:
this.flashMessages.success('Record saved!');
this.flashMessages.danger('Something went wrong.');
this.flashMessages.warning('Please review your input.');
this.flashMessages.info('New updates available.');
Model-level validation:
import { validatePresence, validateFormat } from 'ember-model-validator';
export default class Client extends BaseModel {
validations = {
firstName: { presence: true },
email: { presence: true, format: { with: /^[^@]+@[^@]+$/ } },
phone: { format: { with: /^\d{10}$/, allowBlank: true } },
};
}
Local storage backed properties:
import { localStorage } from 'ember-local-storage-decorator';
export default class MyComponent extends Component {
@localStorage('sidebar-collapsed') declare isCollapsed: boolean;
}
Highcharts integration:
import HighCharts from 'ember-highcharts/components/high-charts';
<template>
<HighCharts @content={{this.chartOptions}} @chartOptions={{this.highchartsConfig}} />
</template>
Code syntax highlighting:
import Shiki from 'ember-shiki/components/shiki';
<template>
<Shiki @code={{this.codeSnippet}} @language="typescript" />
</template>
FontAwesome icons:
import FaIcon from '@fortawesome/ember-fontawesome';
<template>
<FaIcon @icon="check" @prefix="fas" />
<FaIcon @icon="github" @prefix="fab" />
<FaIcon @icon="spinner" @prefix="fas" @spin={{true}} />
</template>