SettingsCtrl.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import { coreModule, appEvents, contextSrv } from 'app/core/core';
  2. import { DashboardModel } from '../../state/DashboardModel';
  3. import $ from 'jquery';
  4. import _ from 'lodash';
  5. import angular from 'angular';
  6. import config from 'app/core/config';
  7. export class SettingsCtrl {
  8. dashboard: DashboardModel;
  9. isOpen: boolean;
  10. viewId: string;
  11. json: string;
  12. alertCount: number;
  13. canSaveAs: boolean;
  14. canSave: boolean;
  15. canDelete: boolean;
  16. sections: any[];
  17. hasUnsavedFolderChange: boolean;
  18. /** @ngInject */
  19. constructor(
  20. private $scope,
  21. private $route,
  22. private $location,
  23. private $rootScope,
  24. private backendSrv,
  25. private dashboardSrv
  26. ) {
  27. // temp hack for annotations and variables editors
  28. // that rely on inherited scope
  29. $scope.dashboard = this.dashboard;
  30. this.$scope.$on('$destroy', () => {
  31. this.dashboard.updateSubmenuVisibility();
  32. setTimeout(() => {
  33. this.$rootScope.appEvent('dash-scroll', { restore: true });
  34. this.dashboard.startRefresh();
  35. });
  36. });
  37. this.canSaveAs = contextSrv.hasEditPermissionInFolders;
  38. this.canSave = this.dashboard.meta.canSave;
  39. this.canDelete = this.dashboard.meta.canSave;
  40. this.buildSectionList();
  41. this.onRouteUpdated();
  42. this.$rootScope.onAppEvent('$routeUpdate', this.onRouteUpdated.bind(this), $scope);
  43. this.$rootScope.appEvent('dash-scroll', { animate: false, pos: 0 });
  44. this.$rootScope.onAppEvent('dashboard-saved', this.onPostSave.bind(this), $scope);
  45. }
  46. buildSectionList() {
  47. this.sections = [];
  48. if (this.dashboard.meta.canEdit) {
  49. this.sections.push({
  50. title: 'General',
  51. id: 'settings',
  52. icon: 'gicon gicon-preferences',
  53. });
  54. this.sections.push({
  55. title: 'Annotations',
  56. id: 'annotations',
  57. icon: 'gicon gicon-annotation',
  58. });
  59. this.sections.push({
  60. title: 'Variables',
  61. id: 'templating',
  62. icon: 'gicon gicon-variable',
  63. });
  64. this.sections.push({
  65. title: 'Links',
  66. id: 'links',
  67. icon: 'gicon gicon-link',
  68. });
  69. }
  70. if (this.dashboard.id && this.dashboard.meta.canSave) {
  71. this.sections.push({
  72. title: 'Versions',
  73. id: 'versions',
  74. icon: 'fa fa-fw fa-history',
  75. });
  76. }
  77. if (this.dashboard.id && this.dashboard.meta.canAdmin) {
  78. this.sections.push({
  79. title: 'Permissions',
  80. id: 'permissions',
  81. icon: 'fa fa-fw fa-lock',
  82. });
  83. }
  84. if (this.dashboard.meta.canMakeEditable) {
  85. this.sections.push({
  86. title: 'General',
  87. icon: 'gicon gicon-preferences',
  88. id: 'make_editable',
  89. });
  90. }
  91. this.sections.push({
  92. title: 'JSON Model',
  93. id: 'dashboard_json',
  94. icon: 'gicon gicon-json',
  95. });
  96. const params = this.$location.search();
  97. const url = this.$location.path();
  98. for (const section of this.sections) {
  99. const sectionParams = _.defaults({ editview: section.id }, params);
  100. section.url = config.appSubUrl + url + '?' + $.param(sectionParams);
  101. }
  102. }
  103. onRouteUpdated() {
  104. this.viewId = this.$location.search().editview;
  105. if (this.viewId) {
  106. this.json = angular.toJson(this.dashboard.getSaveModelClone(), true);
  107. }
  108. if (this.viewId === 'settings' && this.dashboard.meta.canMakeEditable) {
  109. this.viewId = 'make_editable';
  110. }
  111. const currentSection: any = _.find(this.sections, { id: this.viewId } as any);
  112. if (!currentSection) {
  113. this.sections.unshift({
  114. title: 'Not found',
  115. id: '404',
  116. icon: 'fa fa-fw fa-warning',
  117. });
  118. this.viewId = '404';
  119. }
  120. }
  121. openSaveAsModal() {
  122. this.dashboardSrv.showSaveAsModal();
  123. }
  124. saveDashboard() {
  125. this.dashboardSrv.saveDashboard();
  126. }
  127. saveDashboardJson() {
  128. this.dashboardSrv.saveJSONDashboard(this.json).then(() => {
  129. this.$route.reload();
  130. });
  131. }
  132. onPostSave() {
  133. this.hasUnsavedFolderChange = false;
  134. }
  135. hideSettings() {
  136. const urlParams = this.$location.search();
  137. delete urlParams.editview;
  138. setTimeout(() => {
  139. this.$rootScope.$apply(() => {
  140. this.$location.search(urlParams);
  141. });
  142. });
  143. }
  144. makeEditable() {
  145. this.dashboard.editable = true;
  146. this.dashboard.meta.canMakeEditable = false;
  147. this.dashboard.meta.canEdit = true;
  148. this.dashboard.meta.canSave = true;
  149. this.canDelete = true;
  150. this.viewId = 'settings';
  151. this.buildSectionList();
  152. const currentSection: any = _.find(this.sections, { id: this.viewId } as any);
  153. this.$location.url(currentSection.url);
  154. }
  155. deleteDashboard() {
  156. let confirmText = '';
  157. let text2 = this.dashboard.title;
  158. if (this.dashboard.meta.provisioned) {
  159. appEvents.emit('confirm-modal', {
  160. title: 'Cannot delete provisioned dashboard',
  161. text: `
  162. This dashboard is managed by Grafanas provisioning and cannot be deleted. Remove the dashboard from the
  163. config file to delete it.
  164. `,
  165. text2: `
  166. <i>See <a class="external-link" href="http://docs.grafana.org/administration/provisioning/#dashboards" target="_blank">
  167. documentation</a> for more information about provisioning.</i>
  168. `,
  169. text2htmlBind: true,
  170. icon: 'fa-trash',
  171. noText: 'OK',
  172. });
  173. return;
  174. }
  175. const alerts = _.sumBy(this.dashboard.panels, panel => {
  176. return panel.alert ? 1 : 0;
  177. });
  178. if (alerts > 0) {
  179. confirmText = 'DELETE';
  180. text2 = `This dashboard contains ${alerts} alerts. Deleting this dashboard will also delete those alerts`;
  181. }
  182. appEvents.emit('confirm-modal', {
  183. title: 'Delete',
  184. text: 'Do you want to delete this dashboard?',
  185. text2: text2,
  186. icon: 'fa-trash',
  187. confirmText: confirmText,
  188. yesText: 'Delete',
  189. onConfirm: () => {
  190. this.dashboard.meta.canSave = false;
  191. this.deleteDashboardConfirmed();
  192. },
  193. });
  194. }
  195. deleteDashboardConfirmed() {
  196. this.backendSrv.deleteDashboard(this.dashboard.uid).then(() => {
  197. appEvents.emit('alert-success', ['Dashboard Deleted', this.dashboard.title + ' has been deleted']);
  198. this.$location.url('/');
  199. });
  200. }
  201. onFolderChange(folder) {
  202. this.dashboard.meta.folderId = folder.id;
  203. this.dashboard.meta.folderTitle = folder.title;
  204. this.hasUnsavedFolderChange = true;
  205. }
  206. getFolder() {
  207. return {
  208. id: this.dashboard.meta.folderId,
  209. title: this.dashboard.meta.folderTitle,
  210. url: this.dashboard.meta.folderUrl,
  211. };
  212. }
  213. }
  214. export function dashboardSettings() {
  215. return {
  216. restrict: 'E',
  217. templateUrl: 'public/app/features/dashboard/components/DashboardSettings/template.html',
  218. controller: SettingsCtrl,
  219. bindToController: true,
  220. controllerAs: 'ctrl',
  221. transclude: true,
  222. scope: { dashboard: '=' },
  223. };
  224. }
  225. coreModule.directive('dashboardSettings', dashboardSettings);