From dbcefb70f6ac46def629188594515e911c7a2f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 15 Nov 2021 15:12:45 +0100 Subject: [PATCH] Angular: More isolation and removing of unused components (#41630) * Angular: More isolation and removing of unused components * Moved some more and fixed a test --- .../components}/HttpSettingsCtrl.ts | 2 +- .../components}/TlsAuthSettingsCtrl.ts | 2 +- .../components}/plugin_component.ts | 16 +- public/app/angular/index.ts | 3 + .../partials/http_settings.html | 0 .../partials/http_settings_next.html | 0 .../partials/tls_auth_settings.html | 0 public/app/angular/registerComponents.ts | 2 + public/app/features/all.ts | 3 - .../FolderPicker/FolderPickerCtrl.ts | 205 ------------------ .../forms/SaveDashboardAsForm.test.tsx | 4 +- .../forms/SaveDashboardAsForm.tsx | 2 +- .../components/NewDashboardsFolder.tsx | 2 +- .../components/UploadDashboard/index.ts | 1 - .../uploadDashboardDirective.ts | 71 ------ .../app/features/manage-dashboards/index.ts | 5 - .../services/ValidationSrv.ts | 7 +- .../manage-dashboards/utils/validation.ts | 2 +- public/app/features/plugins/all.ts | 2 - .../plugins/variableQueryEditorLoader.tsx | 38 ---- 20 files changed, 17 insertions(+), 350 deletions(-) rename public/app/{features/datasources/settings => angular/components}/HttpSettingsCtrl.ts (86%) rename public/app/{features/datasources/settings => angular/components}/TlsAuthSettingsCtrl.ts (67%) rename public/app/{features/plugins => angular/components}/plugin_component.ts (94%) rename public/app/{features/datasources => angular}/partials/http_settings.html (100%) rename public/app/{features/datasources => angular}/partials/http_settings_next.html (100%) rename public/app/{features/datasources => angular}/partials/tls_auth_settings.html (100%) delete mode 100644 public/app/features/dashboard/components/FolderPicker/FolderPickerCtrl.ts delete mode 100644 public/app/features/manage-dashboards/components/UploadDashboard/index.ts delete mode 100644 public/app/features/manage-dashboards/components/UploadDashboard/uploadDashboardDirective.ts delete mode 100644 public/app/features/manage-dashboards/index.ts delete mode 100644 public/app/features/plugins/variableQueryEditorLoader.tsx diff --git a/public/app/features/datasources/settings/HttpSettingsCtrl.ts b/public/app/angular/components/HttpSettingsCtrl.ts similarity index 86% rename from public/app/features/datasources/settings/HttpSettingsCtrl.ts rename to public/app/angular/components/HttpSettingsCtrl.ts index 190fe246f62..611dd12be7a 100644 --- a/public/app/features/datasources/settings/HttpSettingsCtrl.ts +++ b/public/app/angular/components/HttpSettingsCtrl.ts @@ -8,7 +8,7 @@ coreModule.directive('datasourceHttpSettings', () => { noDirectAccess: '@', showForwardOAuthIdentityOption: '@', }, - templateUrl: 'public/app/features/datasources/partials/http_settings_next.html', + templateUrl: 'public/app/angular/partials/http_settings_next.html', link: { pre: ($scope: any) => { // do not show access option if direct access is disabled diff --git a/public/app/features/datasources/settings/TlsAuthSettingsCtrl.ts b/public/app/angular/components/TlsAuthSettingsCtrl.ts similarity index 67% rename from public/app/features/datasources/settings/TlsAuthSettingsCtrl.ts rename to public/app/angular/components/TlsAuthSettingsCtrl.ts index 3cf49145496..a6e85aa1baf 100644 --- a/public/app/features/datasources/settings/TlsAuthSettingsCtrl.ts +++ b/public/app/angular/components/TlsAuthSettingsCtrl.ts @@ -5,6 +5,6 @@ coreModule.directive('datasourceTlsAuthSettings', () => { scope: { current: '=', }, - templateUrl: 'public/app/features/datasources/partials/tls_auth_settings.html', + templateUrl: 'public/app/angular/partials/tls_auth_settings.html', }; }); diff --git a/public/app/features/plugins/plugin_component.ts b/public/app/angular/components/plugin_component.ts similarity index 94% rename from public/app/features/plugins/plugin_component.ts rename to public/app/angular/components/plugin_component.ts index 59d7e55cee0..be9b7a8e450 100644 --- a/public/app/features/plugins/plugin_component.ts +++ b/public/app/angular/components/plugin_component.ts @@ -5,21 +5,11 @@ import config from 'app/core/config'; import coreModule from 'app/angular/core_module'; import { DataSourceApi, PanelEvents } from '@grafana/data'; -import { importDataSourcePlugin, importAppPlugin } from './plugin_loader'; -import { importPanelPlugin } from './importPanelPlugin'; -import DatasourceSrv from './datasource_srv'; -import { GrafanaRootScope } from 'app/angular/GrafanaCtrl'; +import { importDataSourcePlugin, importAppPlugin } from '../../features/plugins/plugin_loader'; +import { importPanelPlugin } from '../../features/plugins/importPanelPlugin'; /** @ngInject */ -function pluginDirectiveLoader( - $compile: any, - datasourceSrv: DatasourceSrv, - $rootScope: GrafanaRootScope, - $http: any, - $templateCache: any, - $timeout: any, - $location: ILocationService -) { +function pluginDirectiveLoader($compile: any, $http: any, $templateCache: any, $location: ILocationService) { function getTemplate(component: { template: any; templateUrl: any }) { if (component.template) { return Promise.resolve(component.template); diff --git a/public/app/angular/index.ts b/public/app/angular/index.ts index 88e6d011480..2dcaee03cab 100644 --- a/public/app/angular/index.ts +++ b/public/app/angular/index.ts @@ -31,6 +31,9 @@ import './components/info_popover'; import './components/spectrum_picker'; import './components/code_editor/code_editor'; import './components/sql_part/sql_part_editor'; +import './components/HttpSettingsCtrl'; +import './components/TlsAuthSettingsCtrl'; +import './components/plugin_component'; import './GrafanaCtrl'; export { AngularApp } from './AngularApp'; diff --git a/public/app/features/datasources/partials/http_settings.html b/public/app/angular/partials/http_settings.html similarity index 100% rename from public/app/features/datasources/partials/http_settings.html rename to public/app/angular/partials/http_settings.html diff --git a/public/app/features/datasources/partials/http_settings_next.html b/public/app/angular/partials/http_settings_next.html similarity index 100% rename from public/app/features/datasources/partials/http_settings_next.html rename to public/app/angular/partials/http_settings_next.html diff --git a/public/app/features/datasources/partials/tls_auth_settings.html b/public/app/angular/partials/tls_auth_settings.html similarity index 100% rename from public/app/features/datasources/partials/tls_auth_settings.html rename to public/app/angular/partials/tls_auth_settings.html diff --git a/public/app/angular/registerComponents.ts b/public/app/angular/registerComponents.ts index 6b3546e6288..0ef2f7c9a70 100644 --- a/public/app/angular/registerComponents.ts +++ b/public/app/angular/registerComponents.ts @@ -1,6 +1,7 @@ import { getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/core'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; +import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv'; import { getLinkSrv } from 'app/features/panel/panellinks/link_srv'; import coreModule from './core_module'; import { AnnotationsSrv } from './services/annotations_srv'; @@ -11,5 +12,6 @@ export function registerComponents() { coreModule.factory('dashboardSrv', () => getDashboardSrv()); coreModule.factory('datasourceSrv', () => getDataSourceSrv()); coreModule.factory('linkSrv', () => getLinkSrv()); + coreModule.factory('validationSrv', () => validationSrv); coreModule.service('annotationsSrv', AnnotationsSrv); } diff --git a/public/app/features/all.ts b/public/app/features/all.ts index ad19a4a89b0..ec007011106 100644 --- a/public/app/features/all.ts +++ b/public/app/features/all.ts @@ -1,6 +1,3 @@ import './plugins/all'; import './dashboard'; -import './manage-dashboards'; import './profile/all'; -import './datasources/settings/HttpSettingsCtrl'; -import './datasources/settings/TlsAuthSettingsCtrl'; diff --git a/public/app/features/dashboard/components/FolderPicker/FolderPickerCtrl.ts b/public/app/features/dashboard/components/FolderPicker/FolderPickerCtrl.ts deleted file mode 100644 index 2604b54f4ec..00000000000 --- a/public/app/features/dashboard/components/FolderPicker/FolderPickerCtrl.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { map, find } from 'lodash'; -import { IScope } from 'angular'; -import { AppEvents } from '@grafana/data'; - -import coreModule from 'app/angular/core_module'; -import appEvents from 'app/core/app_events'; -import { backendSrv } from 'app/core/services/backend_srv'; -import { ValidationSrv } from 'app/features/manage-dashboards'; -import { ContextSrv } from 'app/core/services/context_srv'; -import { promiseToDigest } from '../../../../angular/promiseToDigest'; -import { createFolder } from 'app/features/manage-dashboards/state/actions'; - -export class FolderPickerCtrl { - declare initialTitle: string; - initialFolderId?: number; - labelClass?: string; - onChange: any; - onLoad: any; - onCreateFolder: any; - enterFolderCreation: any; - exitFolderCreation: any; - declare enableCreateNew: boolean; - declare enableReset: boolean; - rootName = 'General'; - folder: any; - createNewFolder?: boolean; - newFolderName?: string; - newFolderNameTouched?: boolean; - hasValidationError?: boolean; - validationError: any; - isEditor: boolean; - dashboardId?: number; - - /** @ngInject */ - constructor(private validationSrv: ValidationSrv, private contextSrv: ContextSrv, private $scope: IScope) { - this.isEditor = this.contextSrv.isEditor; - - if (this.labelClass === undefined) { - this.labelClass = 'width-7'; - } - - this.loadInitialValue(); - } - - getOptions(query: string) { - const params = { - query, - type: 'dash-folder', - permission: 'Edit', - }; - - return promiseToDigest(this.$scope)( - backendSrv.get('api/search', params).then((result: any) => { - if ( - this.isEditor && - (query === '' || - query.toLowerCase() === 'g' || - query.toLowerCase() === 'ge' || - query.toLowerCase() === 'gen' || - query.toLowerCase() === 'gene' || - query.toLowerCase() === 'gener' || - query.toLowerCase() === 'genera' || - query.toLowerCase() === 'general') - ) { - result.unshift({ title: this.rootName, id: 0 }); - } - - if (this.isEditor && this.enableCreateNew && query === '') { - result.unshift({ title: '-- New folder --', id: -1 }); - } - - if (this.enableReset && query === '' && this.initialTitle !== '') { - result.unshift({ title: this.initialTitle, id: null }); - } - - return map(result, (item) => { - return { text: item.title, value: item.id }; - }); - }) - ); - } - - onFolderChange(option: { value: number; text: string }) { - if (!option) { - option = { value: 0, text: this.rootName }; - } else if (option.value === -1) { - this.createNewFolder = true; - this.enterFolderCreation(); - return; - } - this.onChange({ $folder: { id: option.value, title: option.text } }); - } - - newFolderNameChanged() { - this.newFolderNameTouched = true; - - this.validationSrv - .validateNewFolderName(this.newFolderName) - .then(() => { - this.hasValidationError = false; - }) - .catch((err: any) => { - this.hasValidationError = true; - this.validationError = err.message; - }); - } - - createFolder(evt: any) { - if (evt) { - evt.stopPropagation(); - evt.preventDefault(); - } - - return promiseToDigest(this.$scope)( - createFolder({ title: this.newFolderName }).then((result: { title: string; id: number }) => { - appEvents.emit(AppEvents.alertSuccess, ['Folder created', 'OK']); - - this.closeCreateFolder(); - this.folder = { text: result.title, value: result.id }; - this.onFolderChange(this.folder); - }) - ); - } - - cancelCreateFolder(evt: any) { - if (evt) { - evt.stopPropagation(); - evt.preventDefault(); - } - - this.closeCreateFolder(); - this.loadInitialValue(); - } - - private closeCreateFolder() { - this.exitFolderCreation(); - this.createNewFolder = false; - this.hasValidationError = false; - this.validationError = null; - this.newFolderName = ''; - this.newFolderNameTouched = false; - } - - private loadInitialValue() { - const resetFolder: { text: string; value: any } = { text: this.initialTitle, value: null }; - const rootFolder: { text: string; value: any } = { text: this.rootName, value: 0 }; - - this.getOptions('').then((result: any[]) => { - let folder: { text: string; value: any } | undefined; - - if (this.initialFolderId) { - // @ts-ignore - folder = find(result, { value: this.initialFolderId }); - } else if (this.enableReset && this.initialTitle && this.initialFolderId === null) { - folder = resetFolder; - } - - if (!folder) { - if (this.isEditor) { - folder = rootFolder; - } else { - // We shouldn't assign a random folder without the user actively choosing it on a persisted dashboard - const isPersistedDashBoard = this.dashboardId ? true : false; - if (isPersistedDashBoard) { - folder = resetFolder; - } else { - folder = result.length > 0 ? result[0] : resetFolder; - } - } - } - - this.folder = folder; - - // if this is not the same as our initial value notify parent - if (this.folder.value !== this.initialFolderId) { - this.onChange({ $folder: { id: this.folder.value, title: this.folder.text } }); - } - }); - } -} - -export function folderPicker() { - return { - restrict: 'E', - templateUrl: 'public/app/features/dashboard/components/FolderPicker/template.html', - controller: FolderPickerCtrl, - bindToController: true, - controllerAs: 'ctrl', - scope: { - initialTitle: '<', - initialFolderId: '<', - labelClass: '@', - rootName: '@', - onChange: '&', - onCreateFolder: '&', - enterFolderCreation: '&', - exitFolderCreation: '&', - enableCreateNew: '@', - enableReset: '@', - dashboardId: ' ({})); jest.mock('app/features/expressions/ExpressionDatasource', () => ({})); jest.mock('app/features/manage-dashboards/services/ValidationSrv', () => ({ - validateNewDashboardName: () => true, + validationSrv: { + validateNewDashboardName: () => true, + }, })); jest.spyOn(api, 'searchFolders').mockResolvedValue([]); diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx index bae756865cf..69d5e4ba025 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx @@ -3,7 +3,7 @@ import { Button, Input, Switch, Form, Field, InputControl, Modal } from '@grafan import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { FolderPicker } from 'app/core/components/Select/FolderPicker'; import { SaveDashboardFormProps } from '../types'; -import validationSrv from 'app/features/manage-dashboards/services/ValidationSrv'; +import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv'; interface SaveDashboardAsFormDTO { title: string; diff --git a/public/app/features/folders/components/NewDashboardsFolder.tsx b/public/app/features/folders/components/NewDashboardsFolder.tsx index 80ff2c2a10a..a3ef23bf5bc 100644 --- a/public/app/features/folders/components/NewDashboardsFolder.tsx +++ b/public/app/features/folders/components/NewDashboardsFolder.tsx @@ -5,7 +5,7 @@ import Page from 'app/core/components/Page/Page'; import { createNewFolder } from '../state/actions'; import { getNavModel } from 'app/core/selectors/navModel'; import { StoreState } from 'app/types'; -import validationSrv from '../../manage-dashboards/services/ValidationSrv'; +import { validationSrv } from '../../manage-dashboards/services/ValidationSrv'; const mapStateToProps = (state: StoreState) => ({ navModel: getNavModel(state.navIndex, 'manage-dashboards'), diff --git a/public/app/features/manage-dashboards/components/UploadDashboard/index.ts b/public/app/features/manage-dashboards/components/UploadDashboard/index.ts deleted file mode 100644 index 828b4f76982..00000000000 --- a/public/app/features/manage-dashboards/components/UploadDashboard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { uploadDashboardDirective } from './uploadDashboardDirective'; diff --git a/public/app/features/manage-dashboards/components/UploadDashboard/uploadDashboardDirective.ts b/public/app/features/manage-dashboards/components/UploadDashboard/uploadDashboardDirective.ts deleted file mode 100644 index 5cf013fb472..00000000000 --- a/public/app/features/manage-dashboards/components/UploadDashboard/uploadDashboardDirective.ts +++ /dev/null @@ -1,71 +0,0 @@ -import coreModule from 'app/angular/core_module'; -import appEvents from 'app/core/app_events'; -import angular from 'angular'; -import { AppEvents } from '@grafana/data'; - -const template = ` - - -`; - -/** @ngInject */ -export function uploadDashboardDirective() { - return { - restrict: 'E', - template: template, - scope: { - onUpload: '&', - btnText: '@?', - }, - link: (scope: any, elem: JQuery) => { - scope.btnText = angular.isDefined(scope.btnText) ? scope.btnText : 'Upload .json file'; - - function file_selected(evt: any) { - const files = evt.target.files; // FileList object - const readerOnload = () => { - return (e: any) => { - let dash: any; - try { - dash = JSON.parse(e.target.result); - } catch (err) { - console.error(err); - appEvents.emit(AppEvents.alertError, [ - 'Import failed', - 'JSON -> JS serialization failed: ' + err.message, - ]); - return; - } - - scope.$apply(() => { - scope.onUpload({ dash }); - }); - }; - }; - - let i = 0; - let file = files[i]; - - while (file) { - const reader = new FileReader(); - reader.onload = readerOnload(); - reader.readAsText(file); - i += 1; - file = files[i]; - } - } - - const wnd: any = window; - // Check for the various File API support. - if (wnd.File && wnd.FileReader && wnd.FileList && wnd.Blob) { - // Something - elem[0].addEventListener('change', file_selected, false); - } else { - appEvents.emit(AppEvents.alertError, ['Oops', 'The HTML5 file APIs are not fully supported in this browser']); - } - }, - }; -} - -coreModule.directive('dashUpload', uploadDashboardDirective); diff --git a/public/app/features/manage-dashboards/index.ts b/public/app/features/manage-dashboards/index.ts deleted file mode 100644 index a1790ce0340..00000000000 --- a/public/app/features/manage-dashboards/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Services -export { ValidationSrv } from './services/ValidationSrv'; - -// Components -export * from './components/UploadDashboard'; diff --git a/public/app/features/manage-dashboards/services/ValidationSrv.ts b/public/app/features/manage-dashboards/services/ValidationSrv.ts index f0d4cbb50f1..0e4c570d4f6 100644 --- a/public/app/features/manage-dashboards/services/ValidationSrv.ts +++ b/public/app/features/manage-dashboards/services/ValidationSrv.ts @@ -1,4 +1,3 @@ -import coreModule from 'app/angular/core_module'; import { backendSrv } from 'app/core/services/backend_srv'; const hitTypes = { @@ -63,8 +62,4 @@ export class ValidationSrv { } } -const validationSrv = new ValidationSrv(); - -export default validationSrv; - -coreModule.service('validationSrv', ValidationSrv); +export const validationSrv = new ValidationSrv(); diff --git a/public/app/features/manage-dashboards/utils/validation.ts b/public/app/features/manage-dashboards/utils/validation.ts index d60b3fc95b4..f68d3c30e37 100644 --- a/public/app/features/manage-dashboards/utils/validation.ts +++ b/public/app/features/manage-dashboards/utils/validation.ts @@ -1,4 +1,4 @@ -import validationSrv from '../services/ValidationSrv'; +import { validationSrv } from '../services/ValidationSrv'; import { getBackendSrv } from '@grafana/runtime'; export const validateDashboardJson = (json: string) => { diff --git a/public/app/features/plugins/all.ts b/public/app/features/plugins/all.ts index 9776a8e0b93..fe460be0708 100644 --- a/public/app/features/plugins/all.ts +++ b/public/app/features/plugins/all.ts @@ -1,3 +1 @@ import './datasource_srv'; -import './plugin_component'; -import './variableQueryEditorLoader'; diff --git a/public/app/features/plugins/variableQueryEditorLoader.tsx b/public/app/features/plugins/variableQueryEditorLoader.tsx deleted file mode 100644 index 98e187281d1..00000000000 --- a/public/app/features/plugins/variableQueryEditorLoader.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import coreModule from 'app/angular/core_module'; -import { importDataSourcePlugin } from './plugin_loader'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { LegacyVariableQueryEditor } from '../variables/editor/LegacyVariableQueryEditor'; -import { DataSourcePluginMeta } from '@grafana/data'; -import { TemplateSrv } from '@grafana/runtime'; - -async function loadComponent(meta: DataSourcePluginMeta) { - const dsPlugin = await importDataSourcePlugin(meta); - if (dsPlugin.components.VariableQueryEditor) { - return dsPlugin.components.VariableQueryEditor; - } else { - return LegacyVariableQueryEditor; - } -} - -/** @ngInject */ -function variableQueryEditorLoader(templateSrv: TemplateSrv) { - return { - restrict: 'E', - link: async (scope: any, elem: JQuery) => { - const Component = await loadComponent(scope.currentDatasource.meta); - const props = { - datasource: scope.currentDatasource, - query: scope.current.query, - onChange: scope.onQueryChange, - templateSrv, - }; - ReactDOM.render(, elem[0]); - scope.$on('$destroy', () => { - ReactDOM.unmountComponentAtNode(elem[0]); - }); - }, - }; -} - -coreModule.directive('variableQueryEditorLoader', variableQueryEditorLoader);