@bennerinformatics/ember-fw-gc
Version:
A set of components, controllers, routes, and helpers used in all Group-Control managed FW App System applications
190 lines (170 loc) • 6.38 kB
JavaScript
import Component from '@ember/component';
import EmberError from '@ember/error';
import {computed} from '@ember/object';
import {inject} from '@ember/service';
import {isEmpty, isNone} from '@ember/utils';
import layout from '../templates/components/fw-app-link';
/**
* This component is used to create a link to another FW app. It is used similarly to the Ember `LinkTo` helper.
*
* To use inline, parameters must be provided for the link name, the app ID, and the route name.
* An optional query parameters object can be added at the end. See the [Ember docs](https://guides.emberjs.com/v3.12.0/templates/links/#toc_setting-query-params) for more information on query params
*
* ```handlebars
* <FwAppLink @title='Link Text' @appId='appId' @route='route.name' />
* <FwAppLink @title='Link Text' @appId='appId' @route='route.name' @query={{hash key=value}} />
* ```
*
* When used in block format, the block contents are used in place of link text, so the first parameter is the app ID.
* An optional block parameter is passed containing the app metadata:
*
* ```handlebars
* <FwAppLink @appId='appId' @route='route.name' as |app|>
* <i>{{app.name}}</i>
* </FwAppLink>
* <FwAppLink @appId='appId' @route='route.name' @query={{hash key=value}}>
* <i>Block text</i>
* </FwAppLink>
* ```
*
* If the app is missing or the user does not have access to the app, no HTML will be rendered.
* Use the `has-app` helper to show content when the app is missing.
*
* @public
* @class FwAppLink
* @extends Ember.Component
* @module Components
*/
const FWAppLink = Component.extend({
layout,
tagName: '',
appMeta: inject(),
currentUser: inject(),
/**
* Dynamic parameters array. ***This is deprecated and should not be used. Specify all your parameters***
* @property params
* @type {Array}
* @deprecated
*/
/**
* Link title, will be null in block form
* @property title
* @type {String}
*/
title: null,
/**
* Shortcode of app
* @property appId
* @type {String}
*/
appId: null,
/**
* Route within the app you are linking to
* @property route
* @type {String}
*/
route: '',
/**
* App meta object for the related app. Will be null if the app is not found. Set by `didReceiveAttrs`.
* @property app
* @type {EmberObject}
* @private
*/
app: null,
/**
* This is deprecated. Query parameters for the link. It was set if using the params array and
* passed query params using the `query-params` helper, but the preferred method is using the `@query`
* property, as is described [here](https://guides.emberjs.com/release/routing/query-params/#toc_linkto--component)
*
* @property queryParams
* @type {Object}
* @deprecated
* @private
*/
queryParams: null,
/**
* Computed property of URL encoded query params. This is again deprecated as it relies on the `params` order of the old way
* rather than specified values, as is with the new syntax.
* @property queryString
* @type {Computed String}
* @deprecated
* @private
*/
queryString: computed('queryParams', function() {
// make sure we have a query object and its not empty
let query = this.get('queryParams');
if (isNone(query)) {
return '';
}
let keys = Object.keys(query);
if (isEmpty(keys)) {
return '';
}
// convert all query params into a query string
return `?${keys.map((key) => `${key}=${encodeURIComponent(query[key])}`).join('&')}`;
}),
/**
* Computed property of link URL within the other app.
* @property url
* @type {Computed String}
* @private
*/
url: computed('route', 'app.urlClean', 'queryString', function() {
if (!this.get('app')) {
return null;
}
let route = this.get('route').replace(/\./g, '/');
return `${this.get('app.urlClean')}/#/${route}${this.get('queryString')}`;
}),
/**
* All this stuff about params is deprecated and just there for backwards compatibility. Don't remove,
* but you really shouldn't be using the params attribute in any other app.
*/
didReceiveAttrs() {
this._super(...arguments);
let appId = this.get('appId');
if (appId && this.get('currentUser.apps').includes(appId)) {
this.get('appMeta').findMeta(appId).then((meta) => {
this.set('app', meta);
});
}
// parse params
let params = this.get('params');
if (params) {
let len = params.length;
// query params is the last parameter, fetch that first
let lastParam = params[len - 1];
if (lastParam && lastParam.isQueryParams) {
len--;
this.set('queryParams', lastParam.values);
}
// no parameters remaining means no app
if (len === 0) {
throw new EmberError('App must be defined for FW App Link');
}
// if we have 3 parameters, the first is the title
// ideally would check for HAS_BLOCK here, but Ember does not give access to that
let next = 0;
if (len >= 3) {
this.set('title', params[next++]);
}
// next, fetch the app off the params, always defined
let appId = params[next++];
// skip fetching if we lack permissions, link will be no good
if (this.get('currentUser.apps').includes(appId)) {
this.get('appMeta').findMeta(appId).then((meta) => {
this.set('app', meta);
});
}
// finally, fetch the route if provided
// this is optional in block format, but required in inline due to no HAS_BLOCK
if (len >= 2) {
this.set('route', params[next++]);
}
}
}
});
FWAppLink.reopenClass({
positionalParams: 'params'
});
export default FWAppLink;