Ember AddOns ************ .. highlight:: bash - :doc:`dev-ember` - :doc:`dev-ember-addons-kb` - :doc:`dev-ember-auth` - :doc:`dev-ember-data` - :doc:`dev-ember-patterns` Before adding a new requirement to the project, check Django :doc:`dev-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: .. code-block:: html

Version {{app-version versionOnly=true}}

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 :ref:`npm-patch-install-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: ember-cli-sass ============== Update ``ember-cli-build.js`` and add ``sassOptions``: .. code-block:: javascript 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 :doc:`dev-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. .. note:: We do *not* use https://github.com/django-json-api/django-rest-framework-json-api 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 :ref:`dev-ember-patterns-pagination`. 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"]) // ... } .. tip:: Both ``staticModifiers: true`` and ``staticComponents: true`` in (``ember-cli-build.js``) both need to be set to ``true``. 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: - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat - https://ember-intl.github.io/ember-intl/versions/v5.7.0/docs/helpers/format-date - https://discord.com/channels/480462759797063690/483601670685720591/617001710174601244 ember-modal-dialog ================== I have started using this addon for a simple confirmation dialog. For source code see: - `confirm-delete.js`_ - `confirm-delete.hbs`_ .. _ember_moment: 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 :ref:`ember_data_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. .. code-block:: handlebars {{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}}