DashboardSrv.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import coreModule from 'app/core/core_module';
  2. import { appEvents } from 'app/core/app_events';
  3. import locationUtil from 'app/core/utils/location_util';
  4. import { DashboardModel } from '../state/DashboardModel';
  5. import { removePanel } from '../utils/panel';
  6. export class DashboardSrv {
  7. dashboard: DashboardModel;
  8. /** @ngInject */
  9. constructor(private backendSrv, private $rootScope, private $location) {
  10. appEvents.on('save-dashboard', this.saveDashboard.bind(this), $rootScope);
  11. appEvents.on('panel-change-view', this.onPanelChangeView);
  12. appEvents.on('remove-panel', this.onRemovePanel);
  13. }
  14. create(dashboard, meta) {
  15. return new DashboardModel(dashboard, meta);
  16. }
  17. setCurrent(dashboard: DashboardModel) {
  18. this.dashboard = dashboard;
  19. }
  20. getCurrent(): DashboardModel {
  21. return this.dashboard;
  22. }
  23. onRemovePanel = (panelId: number) => {
  24. const dashboard = this.getCurrent();
  25. removePanel(dashboard, dashboard.getPanelById(panelId), true);
  26. };
  27. onPanelChangeView = options => {
  28. const urlParams = this.$location.search();
  29. // handle toggle logic
  30. if (options.fullscreen === urlParams.fullscreen) {
  31. // I hate using these truthy converters (!!) but in this case
  32. // I think it's appropriate. edit can be null/false/undefined and
  33. // here i want all of those to compare the same
  34. if (!!options.edit === !!urlParams.edit) {
  35. delete urlParams.fullscreen;
  36. delete urlParams.edit;
  37. delete urlParams.panelId;
  38. delete urlParams.tab;
  39. this.$location.search(urlParams);
  40. return;
  41. }
  42. }
  43. if (options.fullscreen) {
  44. urlParams.fullscreen = true;
  45. } else {
  46. delete urlParams.fullscreen;
  47. }
  48. if (options.edit) {
  49. urlParams.edit = true;
  50. } else {
  51. delete urlParams.edit;
  52. delete urlParams.tab;
  53. }
  54. if (options.panelId || options.panelId === 0) {
  55. urlParams.panelId = options.panelId;
  56. } else {
  57. delete urlParams.panelId;
  58. }
  59. this.$location.search(urlParams);
  60. };
  61. handleSaveDashboardError(clone, options, err) {
  62. options = options || {};
  63. options.overwrite = true;
  64. if (err.data && err.data.status === 'version-mismatch') {
  65. err.isHandled = true;
  66. this.$rootScope.appEvent('confirm-modal', {
  67. title: 'Conflict',
  68. text: 'Someone else has updated this dashboard.',
  69. text2: 'Would you still like to save this dashboard?',
  70. yesText: 'Save & Overwrite',
  71. icon: 'fa-warning',
  72. onConfirm: () => {
  73. this.save(clone, options);
  74. },
  75. });
  76. }
  77. if (err.data && err.data.status === 'name-exists') {
  78. err.isHandled = true;
  79. this.$rootScope.appEvent('confirm-modal', {
  80. title: 'Conflict',
  81. text: 'A dashboard with the same name in selected folder already exists.',
  82. text2: 'Would you still like to save this dashboard?',
  83. yesText: 'Save & Overwrite',
  84. icon: 'fa-warning',
  85. onConfirm: () => {
  86. this.save(clone, options);
  87. },
  88. });
  89. }
  90. if (err.data && err.data.status === 'plugin-dashboard') {
  91. err.isHandled = true;
  92. this.$rootScope.appEvent('confirm-modal', {
  93. title: 'Plugin Dashboard',
  94. text: err.data.message,
  95. text2: 'Your changes will be lost when you update the plugin. Use Save As to create custom version.',
  96. yesText: 'Overwrite',
  97. icon: 'fa-warning',
  98. altActionText: 'Save As',
  99. onAltAction: () => {
  100. this.showSaveAsModal();
  101. },
  102. onConfirm: () => {
  103. this.save(clone, { overwrite: true });
  104. },
  105. });
  106. }
  107. }
  108. postSave(clone, data) {
  109. this.dashboard.version = data.version;
  110. // important that these happens before location redirect below
  111. this.$rootScope.appEvent('dashboard-saved', this.dashboard);
  112. this.$rootScope.appEvent('alert-success', ['Dashboard saved']);
  113. const newUrl = locationUtil.stripBaseFromUrl(data.url);
  114. const currentPath = this.$location.path();
  115. if (newUrl !== currentPath) {
  116. this.$location.url(newUrl).replace();
  117. }
  118. return this.dashboard;
  119. }
  120. save(clone, options) {
  121. options = options || {};
  122. options.folderId = options.folderId >= 0 ? options.folderId : this.dashboard.meta.folderId || clone.folderId;
  123. return this.backendSrv
  124. .saveDashboard(clone, options)
  125. .then(this.postSave.bind(this, clone))
  126. .catch(this.handleSaveDashboardError.bind(this, clone, options));
  127. }
  128. saveDashboard(options?, clone?) {
  129. if (clone) {
  130. this.setCurrent(this.create(clone, this.dashboard.meta));
  131. }
  132. if (this.dashboard.meta.provisioned) {
  133. return this.showDashboardProvisionedModal();
  134. }
  135. if (!this.dashboard.meta.canSave && options.makeEditable !== true) {
  136. return Promise.resolve();
  137. }
  138. if (this.dashboard.title === 'New dashboard') {
  139. return this.showSaveAsModal();
  140. }
  141. if (this.dashboard.version > 0) {
  142. return this.showSaveModal();
  143. }
  144. return this.save(this.dashboard.getSaveModelClone(), options);
  145. }
  146. saveJSONDashboard(json: string) {
  147. return this.save(JSON.parse(json), {});
  148. }
  149. showDashboardProvisionedModal() {
  150. this.$rootScope.appEvent('show-modal', {
  151. templateHtml: '<save-provisioned-dashboard-modal dismiss="dismiss()"></save-provisioned-dashboard-modal>',
  152. });
  153. }
  154. showSaveAsModal() {
  155. this.$rootScope.appEvent('show-modal', {
  156. templateHtml: '<save-dashboard-as-modal dismiss="dismiss()"></save-dashboard-as-modal>',
  157. modalClass: 'modal--narrow',
  158. });
  159. }
  160. showSaveModal() {
  161. this.$rootScope.appEvent('show-modal', {
  162. templateHtml: '<save-dashboard-modal dismiss="dismiss()"></save-dashboard-modal>',
  163. modalClass: 'modal--narrow',
  164. });
  165. }
  166. starDashboard(dashboardId, isStarred) {
  167. let promise;
  168. if (isStarred) {
  169. promise = this.backendSrv.delete('/api/user/stars/dashboard/' + dashboardId).then(() => {
  170. return false;
  171. });
  172. } else {
  173. promise = this.backendSrv.post('/api/user/stars/dashboard/' + dashboardId).then(() => {
  174. return true;
  175. });
  176. }
  177. return promise.then(res => {
  178. if (this.dashboard && this.dashboard.id === dashboardId) {
  179. this.dashboard.meta.isStarred = res;
  180. }
  181. return res;
  182. });
  183. }
  184. }
  185. coreModule.service('dashboardSrv', DashboardSrv);