UNPKG

@bennerinformatics/ember-fw-gc

Version:

A set of components, controllers, routes, and helpers used in all Group-Control managed FW App System applications

159 lines (147 loc) 5.84 kB
import AppMeta from '../objects/app-meta'; import {A as emberA, isArray} from '@ember/array'; import EmberObject from '@ember/object'; import Service, {inject} from '@ember/service'; import {isEmpty, isNone} from '@ember/utils'; import RSVP from 'rsvp'; /** * This service is a simple cache of app metas, as we need information from app * metas for a few inter app compoments. * This is done as a service instead of using ember data reduce dependencies and * prevent model conflicts (plus meta does not conform to a JSON model). * * After you inject this service, you have four public methods which can be used to retrieve * appMetas. * * @public * @class AppMetaService * @extends Ember.Service * @module Services */ export default Service.extend({ ajax: inject(), config: inject(), /** * Cache of app metas previously fetched. * Should not be directly accessed, but can be watched * @protected * @property cache * @type {EmberObject} */ cache: EmberObject.create(), /** * App promises that have not yet resolved * @private * @property _promises * @type {EmberObject} */ _promises: EmberObject.create(), /** * Fetches the meta for an app * @public * @param {String} app App ID * @return {Object} Javascript object of app metadata, {size: 0} if no meta found, or null if not fetched */ peekMeta(id) { return this.get('cache').get(id); }, /** * Fetches the metadata for a list of apps * @param {Array} ids Array of string app IDs * @return {Array} Array of coorsponding app IDs */ peekMetas(ids) { return emberA(ids).map((id) => this.peekMeta(id)).reject(isEmpty); }, /** * Internal function to store an array of apps to the cache * @private * @param {Array} apps Array of app meta * @param {Array} ids Array of IDs to ensure are stored */ _cacheApps(apps, ids) { // store all passed in app data let metas = this.get('cache'); if (isArray(apps)) { emberA(apps).forEach((app) => { metas.set(app.appId, AppMeta.create(app)); }); } // for all remaining IDs, store object of size 0 to say we tried to fetch but got nothing if (isArray(ids)) { emberA(ids).forEach((id) => { if (isNone(metas.get(id))) { metas.set(id, AppMeta.create({appId: id, size: 0})); } }); } }, /** * Internal function to request an app meta. Prevents making multiple requests for the same piece of data * @private * @param {String} id App ID to fetch * @return {Promise} Promise that resolves to app meta */ _requestMeta(id) { let promises = this.get('_promises'); let current = promises.get(id); if (!isNone(current)) { return current; } // make the actual fetch let promise = this.get('ajax').request(this.get('config').formGCUrl('apps', 'meta', {ids: id})).then(({apps}) => { this._cacheApps(apps, [id]); promises.set(id, null); // normalize empty to null for this method let meta = this.peekMeta(id); return isEmpty(meta) ? null : meta; }); promises.set(id, promise); return promise; }, /** * Fetches the meta from the server for the specified app * @param {String} id App ID to fetch * @param {Boolean} [reload=false] If true, fetches the data even if loaded. False returns cached data if present * @return {Promise} Promise that resolves to app meta, or resolves to null if no access to the app */ findMeta(id, reload = false) { // if not requested to reload, return previously found meta (if it exists) if (!reload) { let meta = this.peekMeta(id); if (!isNone(meta)) { // empty means we fetched it before, but got nothing, so give null in that case return RSVP.resolve(isEmpty(meta) ? null : meta); } } // if we are reloading or did not find the meta, fetch it return this._requestMeta(id); }, /** * Fetches the meta from the server for the specified app * @param {Array} ids App IDs to fetch * @param {Boolean} [reload=false] If true, fetches the data even if loaded. False returns cached data if present * @return {Promise} Promise that resolves to app meta */ findMetas(ids, reload = false) { // TODO: probably a good idea to validate the IDs are valid apps, not that this method is used outside of the app switcher now let idString; if (reload) { idString = ids.join(','); } else { // if we have no missing apps, return cached metas let missing = emberA(ids).filter((id) => isNone(this.peekMeta(id))); if (isEmpty(missing)) { return RSVP.resolve(this.peekMetas(ids)); } // otherwise fetch just the missing metas idString = missing.join(','); } // fetch all missing metas and return the array of meta // does not use _requestMeta as that function is designed for a single metadata only return this.get('ajax').request(this.get('config').formGCUrl('apps', 'meta', {ids: idString})).then(({apps}) => { this._cacheApps(apps, ids); return this.peekMetas(ids); }); } });