Ember AddOns

Before adding a new requirement to the project, check Django Requirements

ember-cli-app-version

Warning

We are not using this add-on at the moment. For more information, see ember-cli-new-version (below)…

Helper that allows you to show your current app version: https://github.com/ember-cli/ember-cli-app-version

Very easy to use e.g:

<p class="text-center text-gray-500 pt-10">
  Version
  {{app-version versionOnly=true}}
</p>

FileSaver

Warning

14/02/2023, I couldn’t get ember-cli-file-saver working with the most recent version of Ember.

From https://github.com/eligrey/FileSaver.js/:

pnpm install -D file-saver
import { saveAs } from 'file-saver';
saveAs(blob, "pretty-image.png");

ember-cli-flash

Simple, highly configurable flash messages, https://github.com/poteto/ember-cli-flash

ember-cli-new-version

We were installing ember-cli-app-version alongside ember-cli-new-version but for now we are using the kb.py script to update config/environment.js and generate dist/VERSION.txt:

We converted ember-cli-new-version to be a V2 addon, so the index.js file in the root of the project is not being called by the build process to generate dist/VERSION.txt

For more information on using kb.py:

  • To update the config/environment.js file, see Patch, install and publish.

  • To create the dist/VERSION.txt file, run``python ../kb.py –version-txt`` after running the build script (ember bui;d)

Development / Testing

To test locally:

# generate a ``VERSION.txt`` file
python ../kb.py --version
# edit the file, so it as a different version number to ``package.json``
vim dist/VERSION.txt
# move it to the test folder (don't forget to delete before building)
mv dist/VERSION.txt public/assets/

Tip

Example contents for VERSION.txt, 0.1.59

In config/environment.js, set the versionFileName and enableInDev:

newVersion: {
  currentVersion: null,
  versionFileName: 'assets/VERSION.txt',
  enableInDev: true,

ember-cli-sass

Update ember-cli-build.js and add sassOptions:

let app = new EmberApp(defaults, {
  // Add options here
  sassOptions: {
    extension: 'scss'
  }
});

Note

To get started with sass in an Ember project, I renamed app/styles/app.css to app/styles/app.scss and appended all my css files into app.scss.

For more information, see sass.

ember-concurrency

Allows you to write concise, worry-free, cancelable, restartable, asynchronous tasks. http://ember-concurrency.com

ember-cp-validations

To validate models, http://offirgolan.github.io/ember-cp-validations/

ember-css-transitions

To convert Tailwind UI Entering and Leaving transitions to a css-transition:

Tailwind UI   css-transition
------------- ----------------
Entering:     enterActiveClass
From:         enterClass
To:           enterToClass
Leaving:      leaveActiveClass
From:         leaveClass
To:           leaveToClass

For more information, see the documentation for ember-css-transitions and Tailwind UI Dropdowns with Ember

ember-django-adapter

We use the https://github.com/dustinfarris/ember-django-adapter to connect to Django REST Framework.

ember-file-upload

Note

I couldn’t get ember-file-upload working, so ended up using https://github.com/knownasilya/ember-plupload (I think Tim has ember-file-upload working).

Here is some sample code plan-detail.hbs

ember-font-awesome

To use the Font Awesome icons.

ember-infinity

We didn’t get on too well with ember-infinity and concurrency, so this section has been removed for now.

Information on pagination was deleted from here. Revised notes can be found at Pagination (JSON API).

ember-intl

Configure in the application route, app/routes/application.js:

export default class ApplicationRoute extends Route {
  @service intl

  beforeModel(transition) {
    this.intl.setLocale(["en-uk"])
    // ...
  }

Usage:

{{format-date
  ticket.created
  day="numeric"
  month="numeric"
  year="numeric"
}}

Date and time:

{{format-date
  ticket.created
  year="numeric"
  month="numeric"
  day="numeric"
  hour="numeric"
  minute="numeric"
}}

Other options:

month="short"
weekday="long"

Date formats:

ember-modal-dialog

I have started using this addon for a simple confirmation dialog.

For source code see:

ember-moment

Note

14/08/2021, We are going to try ember-intl instead… (ref https://github.com/stefanpenner/ember-moment/issues/340)

Tip

To set-up a date field in an Ember model, see Date / Time.

I had to install ember-cli-moment-shim as well as ember-moment:

yarn add ember-moment ember-cli-moment-shim

e.g.

{{moment-format note.created "DD/MM/YYYY HH:mm"}}

ember-promise-modals

We haven’t used this yet, but it looks great: https://simplabs.github.io/ember-promise-modals/

For more information, see, Managing modal dialogs in Ember.js with Promises, https://simplabs.com/blog/2021/08/26/managing-modals-in-ember/

ember-route-action-helper

Recommended by https://twitter.com/EmmaDelescolle to bubble closure actions in routes.

ember-simple-auth

For authentication, we use https://github.com/simplabs/ember-simple-auth with Django REST framework Token Authentication

This video explains how to setup and use Ember Simple Auth

Route

Check a user is authenticated:

import { inject as service } from "@ember/service"

export default class MyRoute extends Route {
  @service session

  beforeModel(transition) {
    // if not authenticated, transition to 'authenticate'
    this.session.requireAuthentication(transition, "authenticate")
  }

Tip

PJK 24/11/2021, Changed the transition to authenticate rather than login. Not sure if this is correct or not?!

Controller (login)

import { inject as service } from "@ember/service"

export default class LoginController extends Controller {
  @service session

  @action
  async login(event) {
    event.preventDefault()
    try {
      await this.session.authenticate('authenticator:token', this.username, this.password)
    } catch(error) {
      ...

Tip

authenticator:token is the name of the authenticator we want to use. this.username and this.password are passed on to the authenticator.

Authenticator (write our own)

// app/authenticators/token.js
import Base from 'ember-simple-auth/authenticators/base'

export default Base.extend({

  async authenticate(username, password) {
    let response = await fetch('/api/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username, password
      })
    })

    if (response.ok) {
      return response.json()
    } else {
      let error = await response.text()
      throw new Error(error)
    }
  })

  async restore(data) {
    let { token } = data
    if (token) {
      return data
    } else {
      throw 'no valid session data'
    }
  }

Tip

The authenticate method automatically stores the token in the session.

Session Store

// app/session-stores/application.js
import CookieStore from 'ember-simple-auth/session-stores/cookie'

export default class ApplicationSessionStore extends CookieStore {
}

Adapter

import { inject as service } from "@ember/service"

export default class ApplicationAdapter extends JSONAPIAdapter {
  @service session

  @computed('session.data.authenticated.token')
  get headers() {
    let headers = {}
    if (this.session.isAuthenticated) {
      headers['token'] = this.session.data.authenticated.token
    }
    return headers
  }
}

Route (login)

The login route should not be accessible to a logged in user:

import { inject as service } from "@ember/service"

export default class LoginRoute extends Route {
  @service session

  beforeModel(transition) {
    this.session.prohibitAuthentication("index")
  }

Note

The user will be taken to the index route if they browse to the login route (and are already logged in).

Components

{{#if session.isAuthenticated}}
  <button type="button" {{on 'click' this.logout}}>
import { inject as service } from "@ember/service"

export default class NavComponent extends Component {
  @service session

  @action
  logout()
    this.session.invalidate()

Current Contact

From Managing a Current User

Warning

The following code doesn’t get called if installed into an ember add on, so copy into the project!

Use the following code in front/app/services/session.js:

import { inject as service } from "@ember/service"
import BaseSessionService from "ember-simple-auth/services/session"

export default class SessionService extends BaseSessionService {
  @service currentContact

  async handleAuthentication() {
    super.handleAuthentication(...arguments)
    try {
      await this.currentContact.load()
    } catch (err) {
      await this.invalidate()
    }
  }
}

FileSaver

06/09/2021, I am using FileSaver.js instead of ember-cli-file-saver:

npm install ember-auto-import
npm install file-saver

For more details, see:

<Report::Button
  @reportSlug={{"contact-tickets"}}
  @reportParameters={{this.reportParameters}}
/>