registry.tsx 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /* eslint no-console:0 */
  2. import {DefaultIssuePlugin} from 'sentry/plugins/defaultIssuePlugin';
  3. import {DefaultPlugin} from 'sentry/plugins/defaultPlugin';
  4. import type SessionStackPlugin from 'sentry/plugins/sessionstack';
  5. import type {Plugin} from 'sentry/types/integrations';
  6. import {defined} from 'sentry/utils';
  7. type PluginComponent =
  8. | typeof DefaultIssuePlugin
  9. | typeof DefaultPlugin
  10. | typeof SessionStackPlugin;
  11. export default class Registry {
  12. plugins: Record<string, PluginComponent> = {};
  13. assetCache: Record<string, HTMLScriptElement> = {};
  14. isLoaded(data: Plugin) {
  15. return defined(this.plugins[data.id]);
  16. }
  17. load(
  18. data: Plugin,
  19. callback: (instance: DefaultIssuePlugin | DefaultPlugin | SessionStackPlugin) => void
  20. ) {
  21. let remainingAssets = data.assets.length;
  22. // TODO(dcramer): we should probably register all valid plugins
  23. const finishLoad = () => {
  24. if (!defined(this.plugins[data.id])) {
  25. if (data.type === 'issue-tracking') {
  26. this.plugins[data.id] = DefaultIssuePlugin;
  27. } else {
  28. this.plugins[data.id] = DefaultPlugin;
  29. }
  30. }
  31. console.info(
  32. '[plugins] Loaded ' + data.id + ' as {' + this.plugins[data.id].name + '}'
  33. );
  34. callback(this.get(data));
  35. };
  36. if (remainingAssets === 0) {
  37. finishLoad();
  38. return;
  39. }
  40. const onAssetLoaded = function () {
  41. remainingAssets--;
  42. if (remainingAssets === 0) {
  43. finishLoad();
  44. }
  45. };
  46. const onAssetFailed = function (asset: {url: string}) {
  47. remainingAssets--;
  48. console.error('[plugins] Failed to load asset ' + asset.url);
  49. if (remainingAssets === 0) {
  50. finishLoad();
  51. }
  52. };
  53. // TODO(dcramer): what do we do on failed asset loading?
  54. data.assets.forEach(asset => {
  55. if (!defined(this.assetCache[asset.url])) {
  56. console.info('[plugins] Loading asset for ' + data.id + ': ' + asset.url);
  57. const s = document.createElement('script');
  58. s.src = asset.url;
  59. s.onload = onAssetLoaded.bind(this);
  60. s.onerror = onAssetFailed.bind(this, asset);
  61. s.async = true;
  62. document.body.appendChild(s);
  63. this.assetCache[asset.url] = s;
  64. } else {
  65. onAssetLoaded();
  66. }
  67. });
  68. }
  69. get(data: Plugin) {
  70. const cls = this.plugins[data.id];
  71. if (!defined(cls)) {
  72. throw new Error('Attempted to ``get`` an unloaded plugin: ' + data.id);
  73. }
  74. return new cls(data);
  75. }
  76. add(id: string, cls: PluginComponent) {
  77. this.plugins[id] = cls;
  78. }
  79. }