panel_model.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { Emitter } from 'app/core/utils/emitter';
  2. import _ from 'lodash';
  3. import { PANEL_OPTIONS_KEY_PREFIX } from 'app/core/constants';
  4. export interface GridPos {
  5. x: number;
  6. y: number;
  7. w: number;
  8. h: number;
  9. static?: boolean;
  10. }
  11. const notPersistedProperties: { [str: string]: boolean } = {
  12. events: true,
  13. fullscreen: true,
  14. isEditing: true,
  15. hasRefreshed: true,
  16. };
  17. // For angular panels we need to clean up properties when changing type
  18. // To make sure the change happens without strange bugs happening when panels use same
  19. // named property with different type / value expectations
  20. // This is not required for react panels
  21. const mustKeepProps: { [str: string]: boolean } = {
  22. id: true,
  23. gridPos: true,
  24. type: true,
  25. title: true,
  26. scopedVars: true,
  27. repeat: true,
  28. repeatIteration: true,
  29. repeatPanelId: true,
  30. repeatDirection: true,
  31. repeatedByRow: true,
  32. minSpan: true,
  33. collapsed: true,
  34. panels: true,
  35. targets: true,
  36. datasource: true,
  37. timeFrom: true,
  38. timeShift: true,
  39. hideTimeOverride: true,
  40. maxDataPoints: true,
  41. interval: true,
  42. description: true,
  43. links: true,
  44. fullscreen: true,
  45. isEditing: true,
  46. hasRefreshed: true,
  47. events: true,
  48. cacheTimeout: true,
  49. nullPointMode: true,
  50. };
  51. const defaults: any = {
  52. gridPos: { x: 0, y: 0, h: 3, w: 6 },
  53. datasource: null,
  54. targets: [{}],
  55. };
  56. export class PanelModel {
  57. id: number;
  58. gridPos: GridPos;
  59. type: string;
  60. title: string;
  61. alert?: any;
  62. scopedVars?: any;
  63. repeat?: string;
  64. repeatIteration?: number;
  65. repeatPanelId?: number;
  66. repeatDirection?: string;
  67. repeatedByRow?: boolean;
  68. minSpan?: number;
  69. collapsed?: boolean;
  70. panels?: any;
  71. soloMode?: boolean;
  72. targets: any[];
  73. datasource: string;
  74. thresholds?: any;
  75. snapshotData?: any;
  76. timeFrom?: any;
  77. timeShift?: any;
  78. hideTimeOverride?: any;
  79. maxDataPoints?: number;
  80. interval?: string;
  81. description?: string;
  82. links?: [];
  83. // non persisted
  84. fullscreen: boolean;
  85. isEditing: boolean;
  86. hasRefreshed: boolean;
  87. events: Emitter;
  88. constructor(model) {
  89. this.events = new Emitter();
  90. // copy properties from persisted model
  91. for (const property in model) {
  92. this[property] = model[property];
  93. }
  94. // defaults
  95. _.defaultsDeep(this, _.cloneDeep(defaults));
  96. }
  97. getOptions() {
  98. return this[this.getOptionsKey()] || {};
  99. }
  100. updateOptions(options: object) {
  101. const update: any = {};
  102. update[this.getOptionsKey()] = options;
  103. Object.assign(this, update);
  104. this.render();
  105. }
  106. private getOptionsKey() {
  107. return 'options-' + this.type;
  108. }
  109. getSaveModel() {
  110. const model: any = {};
  111. for (const property in this) {
  112. if (notPersistedProperties[property] || !this.hasOwnProperty(property)) {
  113. continue;
  114. }
  115. if (_.isEqual(this[property], defaults[property])) {
  116. continue;
  117. }
  118. model[property] = _.cloneDeep(this[property]);
  119. }
  120. return model;
  121. }
  122. setViewMode(fullscreen: boolean, isEditing: boolean) {
  123. this.fullscreen = fullscreen;
  124. this.isEditing = isEditing;
  125. this.events.emit('panel-size-changed');
  126. }
  127. updateGridPos(newPos: GridPos) {
  128. let sizeChanged = false;
  129. if (this.gridPos.w !== newPos.w || this.gridPos.h !== newPos.h) {
  130. sizeChanged = true;
  131. }
  132. this.gridPos.x = newPos.x;
  133. this.gridPos.y = newPos.y;
  134. this.gridPos.w = newPos.w;
  135. this.gridPos.h = newPos.h;
  136. if (sizeChanged) {
  137. this.events.emit('panel-size-changed');
  138. }
  139. }
  140. resizeDone() {
  141. this.events.emit('panel-size-changed');
  142. }
  143. refresh() {
  144. this.hasRefreshed = true;
  145. this.events.emit('refresh');
  146. }
  147. render() {
  148. if (!this.hasRefreshed) {
  149. this.refresh();
  150. } else {
  151. this.events.emit('render');
  152. }
  153. }
  154. panelInitialized() {
  155. this.events.emit('panel-initialized');
  156. }
  157. changeType(pluginId: string, fromAngularPanel: boolean) {
  158. this.type = pluginId;
  159. // for now we need to remove alert rules when changing type
  160. delete this.alert;
  161. // for angular panels only we need to remove all events and let angular panels do some cleanup
  162. if (fromAngularPanel) {
  163. this.destroy();
  164. for (const key of _.keys(this)) {
  165. if (mustKeepProps[key] || key.indexOf(PANEL_OPTIONS_KEY_PREFIX) === 0) {
  166. continue;
  167. }
  168. delete this[key];
  169. console.log('deleting ', key);
  170. }
  171. }
  172. }
  173. destroy() {
  174. this.events.emit('panel-teardown');
  175. this.events.removeAllListeners();
  176. }
  177. }