SettingsCtrl.ts 7.1 KB

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