VisDefinitionManager.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. 'use strict';
  2. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  3. /*
  4. *+------------------------------------------------------------------------+
  5. *| Licensed Materials - Property of IBM
  6. *| IBM Cognos Products: Content Explorer
  7. *| (C) Copyright IBM Corp. 2015, 2020
  8. *|
  9. *| US Government Users Restricted Rights - Use, duplication or disclosure
  10. *| restricted by GSA ADP Schedule Contract with IBM Corp.
  11. *+------------------------------------------------------------------------+
  12. */
  13. /**
  14. *
  15. * Override this class to provide localized labels,description for vis properties and slots.
  16. *
  17. */
  18. define(['underscore', '../../lib/@waca/core-client/js/core-client/ui/core/Class', '../../lib/@waca/dashboard-common/dist/api/Error', './VisDefinitions', '../../DynamicFileLoader', 'dashboard-analytics/widgets/livewidget/nls/StringResources', '../../widgets/livewidget/util/VisUtil', '../vipr/VIPRLibraries'], function (_, Class, APIError, VisDefinitions, DynamicFileLoader, StringResources, VisUtil, VIPRLibraries) {
  19. // List of providers managed by the visDefinitionManager
  20. var PROVIDERS = ['dashboard-analytics/visualizations/definitions/providers/VIPR3Provider', 'dashboard-analytics/visualizations/definitions/providers/LocalProvider'];
  21. var WILDCARD_KEY = '*';
  22. var VisDefinitionManager = Class.extend({
  23. initialAllPromise: null,
  24. extensionsPromise: null,
  25. initializeProvidersPromise: null,
  26. /**
  27. * This class is singleton, do not cache dashboard api.
  28. * @param params - expects a dashboardApi to access the dashboard API
  29. */
  30. init: function init(params) {
  31. this.logger = params.dashboardApi.getGlassCoreSvc('.Logger');
  32. if (params.visDefinitions) {
  33. this.visDefinitions = new VisDefinitions({
  34. jsonDefinitions: params.visDefinitions
  35. });
  36. }
  37. this.ajaxSvc = params.dashboardApi.getGlassCoreSvc('.Ajax');
  38. this.initialAllPromise = null;
  39. // initialize all visDefinition providers
  40. this.initializeProviders = this._initProviders(params);
  41. },
  42. _getExtensions: function _getExtensions(dashboardApi) {
  43. if (!this.extensionsPromise) {
  44. var visualizationExtensionConfig = dashboardApi.getCollectionConfig('visualizationExtension');
  45. if (visualizationExtensionConfig) {
  46. var collectionId = visualizationExtensionConfig.id;
  47. // load the collection
  48. this.extensionsPromise = new Promise(function (resolve, reject) {
  49. dashboardApi.findGlassCollection(collectionId).then(function (extensions) {
  50. // convert visualization extensions array to a map (id as key)
  51. var extentionsMap = _.object(_.map(extensions, function (ext) {
  52. // ids that are not fully qualified will be prefixed by the feature id
  53. var prefix = 'com.ibm.bi.dashboard.';
  54. var idParts = ext.id && ext.id.split(prefix);
  55. var id = idParts.length === 1 ? idParts[0] : idParts[1];
  56. return [id, ext];
  57. }));
  58. // @todo temporary code to temporarily enable a visualization only on dev mode
  59. // edit the extension entry from perspectives/dashboard/contrib/visualizationExtensionCA.json
  60. var enabledList = ['com.ibm.vis.comet'];
  61. if (dashboardApi.isDevInstall()) {
  62. _.each(enabledList, function (visId) {
  63. if (_.isObject(extentionsMap[visId])) {
  64. extentionsMap[visId].active = true;
  65. }
  66. });
  67. }
  68. resolve(extentionsMap);
  69. }).catch(reject);
  70. });
  71. } else {
  72. // no extensions available... move on...
  73. this.extensionsPromise = Promise.resolve({});
  74. }
  75. }
  76. return this.extensionsPromise;
  77. },
  78. /**
  79. * Load all providers defined on the provider list
  80. */
  81. _initProviders: function _initProviders(params) {
  82. if (!this.initializeProvidersPromise) {
  83. var providers = [];
  84. this.initializeProvidersPromise = DynamicFileLoader.load(params.providers ? params.providers : PROVIDERS).then(function (modules) {
  85. _.each(modules, function (Cls) {
  86. providers.push(new (Function.prototype.bind.call(Cls, null, params))());
  87. });
  88. return providers;
  89. });
  90. }
  91. return this.initializeProvidersPromise;
  92. },
  93. /**
  94. * Clear the known vis definitions so they can be refreshed.
  95. */
  96. clearDefinitions: function clearDefinitions() {
  97. this.visDefinitions = null;
  98. this.initialAllPromise = null;
  99. this.initializeProviders.then(function (providers) {
  100. _.each(providers, function (provider) {
  101. provider.clear();
  102. });
  103. });
  104. },
  105. /**
  106. * Loads all vis definitions from the server
  107. */
  108. _loadAllDefinitions: function _loadAllDefinitions(dashboardApi) {
  109. var _this = this;
  110. var visDefinitions = this._getVisDefinitions();
  111. this.initialAllPromise = this.initializeProviders.then(function (providers) {
  112. return Promise.all(_.map(providers, function (provider) {
  113. return provider.getDefinitions();
  114. })).then(function (definitions) {
  115. return _this._extendDefinitions([].concat.apply([], definitions), dashboardApi);
  116. }).then(function (extendDefinitions) {
  117. visDefinitions.jsonDefinitions = _.sortBy(extendDefinitions, 'label');
  118. return visDefinitions;
  119. });
  120. });
  121. return this.initialAllPromise;
  122. },
  123. /**
  124. * Recurrsively deep extend the target definition with the source definition along
  125. * with a wildcard source which applies to all objects when a specific source is not defined.
  126. * The source should take precedence over the wildcard.
  127. * {
  128. // Example 1: Disable multiMeasure on column chart
  129. 'com.ibm.vis.rave2bundlecolumn': {
  130. 'dataSlots': {
  131. 'values': {
  132. 'multiMeasure': false
  133. }
  134. }
  135. },
  136. // Example 2: Disable multiMeasure on all visualizations
  137. '*': {
  138. 'dataSlots': {
  139. 'values': {
  140. 'multiMeasure': false
  141. }
  142. }
  143. },
  144. // Example 3: Only allow 1 mapping for all slots and mutliMeasure is disabled on all visualizations
  145. '*': {
  146. 'dataSlots': {
  147. 'values': {
  148. 'multiMeasure': false
  149. },
  150. '*': {
  151. 'maxItems': 1
  152. }
  153. }
  154. }
  155. }
  156. * @param {Object} target target defiinition object to override
  157. * @param {Object} source source definition object to override with
  158. * @param {Object} wildcard wildcard definition object to override with against all objects
  159. */
  160. _extendDefinitionObject: function _extendDefinitionObject(target, source, wildcard) {
  161. var extended = target;
  162. // Attempt to extend the object only if at least one canidates exists
  163. if (source || wildcard) {
  164. var sourceKeys = source ? Object.keys(source) : [];
  165. var wildcardKeys = wildcard ? Object.keys(wildcard) : [];
  166. var allKeys = [].concat(Object.keys(target), sourceKeys, wildcardKeys);
  167. // Ensure we are not extending the original definition, original definition may also be frozen
  168. extended = _.clone(target);
  169. for (var _iterator = allKeys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
  170. var _ref;
  171. if (_isArray) {
  172. if (_i >= _iterator.length) break;
  173. _ref = _iterator[_i++];
  174. } else {
  175. _i = _iterator.next();
  176. if (_i.done) break;
  177. _ref = _i.value;
  178. }
  179. var key = _ref;
  180. // wildcard should not exist in the target
  181. if (key === WILDCARD_KEY) {
  182. continue;
  183. }
  184. var extKey = Array.isArray(target) ? target[key].id : key;
  185. // NOTE. `typeof null` is also 'object'
  186. if (target[key] && _typeof(target[key]) === 'object') {
  187. // deep extend with extension and wildcard
  188. // source takes precedence over the wildcard
  189. var childSource = source && source[extKey] || wildcard && wildcard[extKey];
  190. var childWildcard = source && source[WILDCARD_KEY] || wildcard && wildcard[WILDCARD_KEY];
  191. extended[key] = this._extendDefinitionObject(target[key], childSource, childWildcard);
  192. } else if (key !== 'id') {
  193. // shallow extend all attrubutes giving precedence to the source over the wildecard
  194. if (source && source.hasOwnProperty(extKey)) {
  195. extended[key] = source[extKey];
  196. } else if (wildcard && wildcard.hasOwnProperty(extKey)) {
  197. extended[key] = wildcard[extKey];
  198. }
  199. }
  200. }
  201. }
  202. return extended;
  203. },
  204. _extendDefinitions: function _extendDefinitions(definitions, dashboardApi) {
  205. var _this2 = this;
  206. // fetch the visualization extensions
  207. return this._getExtensions(dashboardApi).then(function (extensions) {
  208. // exclude all inactive definitions
  209. var activeDefs = _.filter(definitions, function (definition) {
  210. var ext = extensions[definition.id] || { active: true };
  211. return ext.active !== false;
  212. });
  213. var extendedDefs = _.map(activeDefs, function (definition) {
  214. return _this2._extendDefinitionObject(definition, extensions[definition.id], extensions[WILDCARD_KEY]);
  215. });
  216. return extendedDefs;
  217. }).catch(function () {
  218. return definitions;
  219. });
  220. },
  221. getBundles: function getBundles() {
  222. return this.getAll().then(function (all) {
  223. return all.jsonDefinitions;
  224. });
  225. },
  226. /**
  227. * Load the VisDefinitions list from server.
  228. * Returns a cached copy if this operation is already done.
  229. * @returns a promise
  230. */
  231. getAll: function getAll(dashboardApi) {
  232. if (!dashboardApi) {
  233. //The only time there should be no dashboard API is when running unit tests,
  234. //and in that case, visDefinitions should be provided in the constructor.
  235. return Promise.resolve(this.visDefinitions);
  236. }
  237. if (!this.initialAllPromise) {
  238. return this._loadAllDefinitions(dashboardApi);
  239. }
  240. return this.initialAllPromise;
  241. },
  242. findProvider: function findProvider(id) {
  243. return this.initializeProviders.then(function (providers) {
  244. var promises = _.map(providers, function (provider) {
  245. // resolve the promise with the provider (if contains) or undefined (if doesn't contain)
  246. return provider.contains(id).then(function (contains) {
  247. return contains ? provider : undefined;
  248. }).catch(function () {
  249. return undefined;
  250. });
  251. });
  252. return Promise.all(promises).then(function (results) {
  253. // see if there was promise that resolved with a provider
  254. var provider = _.find(results, function (result) {
  255. return !!result;
  256. });
  257. if (provider) {
  258. return provider;
  259. } else {
  260. throw new Error('Invalid provider');
  261. }
  262. });
  263. });
  264. },
  265. /**
  266. * Loads a single vis definition from the server
  267. */
  268. _loadDefinition: function _loadDefinition(id) {
  269. var visDefinitions = this._getVisDefinitions();
  270. return this.findProvider(id).then(function (provider) {
  271. return provider.getDefinition(id).then(function (data) {
  272. visDefinitions.mapDefinitionsById[id] = data;
  273. return data;
  274. });
  275. }).catch(function () {
  276. throw VisUtil.createVisDefinitionLoadingError(id);
  277. });
  278. },
  279. /**
  280. * Load VisDefinition for specified id
  281. * Updates map in this.visDefinitions on getting the spec
  282. * Returns a cached version if this operation is already done
  283. * @returns a promise
  284. */
  285. get: function get(id) {
  286. var data = this.visDefinitions && this.visDefinitions.mapDefinitionsById[id];
  287. if (!data) {
  288. return this._loadDefinition(id);
  289. }
  290. return Promise.resolve(data);
  291. },
  292. refreshProviders: function refreshProviders(dashboardApi) {
  293. var _this3 = this;
  294. var visDefinitions = this._getVisDefinitions();
  295. return this.initializeProviders.then(function () {
  296. var providers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  297. return Promise.all(_.map(providers, function (provider) {
  298. return provider.refreshProvider(dashboardApi);
  299. })).then(function (definitions) {
  300. return _this3._extendDefinitions([].concat.apply([], definitions), dashboardApi);
  301. }).then(function (extendDefinitions) {
  302. visDefinitions.jsonDefinitions = _.sortBy(extendDefinitions, 'label');
  303. //Remove cached visDefinitions.mapDefinitionsById that are no longer valid (i.e. got deleted from CM for custom vis)
  304. visDefinitions.removeObsoleteCachedVisDefinitions();
  305. return visDefinitions;
  306. });
  307. });
  308. },
  309. refresh: function refresh(visId) {
  310. var _this4 = this;
  311. return this.findProvider(visId).then(function (provider) {
  312. if (provider) {
  313. return provider.refresh(visId).then(function (newDef) {
  314. //update cache
  315. if (newDef.renderer) {
  316. _this4.visDefinitions.mapDefinitionsById[visId] = newDef;
  317. }
  318. return newDef;
  319. });
  320. }
  321. }).catch(function () {
  322. var msg = StringResources.get('loadVisDefinitionError', { id: visId });
  323. throw new APIError({
  324. msg: msg,
  325. params: {
  326. errorInfo: {
  327. id: visId,
  328. errorCode: VIPRLibraries.LOAD_DEFINITION_ERROR,
  329. errorMessage: msg
  330. }
  331. }
  332. });
  333. });
  334. },
  335. _getVisDefinitions: function _getVisDefinitions() {
  336. if (!this.visDefinitions) {
  337. this.visDefinitions = new VisDefinitions();
  338. }
  339. return this.visDefinitions;
  340. }
  341. });
  342. var mgr = null;
  343. return function (params) {
  344. if (!mgr || params.providers) {
  345. mgr = new VisDefinitionManager(params);
  346. }
  347. return mgr;
  348. };
  349. });
  350. //# sourceMappingURL=VisDefinitionManager.js.map