hookStore.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import {createStore, StoreDefinition} from 'reflux';
  2. import {HookName, Hooks} from 'sentry/types/hooks';
  3. interface Internals {
  4. // XXX(epurkhiser): We could type this as {[H in HookName]?:
  5. // Array<Hooks[H]>}, however this causes typescript to produce a complex
  6. // union that it complains is 'too complex'
  7. hooks: any;
  8. }
  9. // TODO: Make generic and match against a map of allowed callbacks if we expand this pattern.
  10. type HookCallback = (...args: any[]) => void;
  11. interface HookStoreDefinition extends StoreDefinition, Internals {
  12. add<H extends HookName>(hookName: H, callback: Hooks[H]): void;
  13. get<H extends HookName>(hookName: H): Array<Hooks[H]>;
  14. getCallback<H extends HookName>(hookName: H, key: string): HookCallback | undefined;
  15. init(): void;
  16. persistCallback<H extends HookName>(
  17. hookName: H,
  18. key: string,
  19. value: HookCallback
  20. ): void;
  21. remove<H extends HookName>(hookName: H, callback: Hooks[H]): void;
  22. }
  23. const storeConfig: HookStoreDefinition = {
  24. hooks: {},
  25. hookCallbacks: {},
  26. init() {
  27. // XXX: Do not use `this.listenTo` in this store. We avoid usage of reflux
  28. // listeners due to their leaky nature in tests.
  29. this.hooks = {};
  30. this.hookCallbacks = {}; // For persisting hook pure functions / useX react hooks remotely.
  31. },
  32. add(hookName, callback) {
  33. if (this.hooks[hookName] === undefined) {
  34. this.hooks[hookName] = [];
  35. }
  36. this.hooks[hookName].push(callback);
  37. this.trigger(hookName, this.hooks[hookName]);
  38. },
  39. remove(hookName, callback) {
  40. if (this.hooks[hookName] === undefined) {
  41. return;
  42. }
  43. this.hooks[hookName] = this.hooks[hookName]!.filter(cb => cb !== callback);
  44. this.trigger(hookName, this.hooks[hookName]);
  45. },
  46. get(hookName) {
  47. return this.hooks[hookName]! || [];
  48. },
  49. persistCallback(hookName, key, value) {
  50. if (this.hookCallbacks[hookName] === undefined) {
  51. this.hookCallbacks[hookName] = {};
  52. }
  53. if (this.hookCallbacks[hookName][key] !== value) {
  54. this.hookCallbacks[hookName][key] = value;
  55. }
  56. },
  57. getCallback(hookName, key) {
  58. return this.hookCallbacks[hookName]?.[key];
  59. },
  60. };
  61. /**
  62. * HookStore is used to allow extensibility into Sentry's frontend via
  63. * registration of 'hook functions'.
  64. *
  65. * This functionality is primarily used by the SASS sentry.io product.
  66. */
  67. const HookStore = createStore(storeConfig);
  68. export default HookStore;