mirror of
https://github.com/grafana/grafana.git
synced 2024-11-30 12:44:10 -06:00
Angular: More isolation and removing of unused components (#41630)
* Angular: More isolation and removing of unused components * Moved some more and fixed a test
This commit is contained in:
parent
8ea75c9401
commit
dbcefb70f6
@ -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
|
@ -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',
|
||||
};
|
||||
});
|
@ -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);
|
@ -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';
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
import './plugins/all';
|
||||
import './dashboard';
|
||||
import './manage-dashboards';
|
||||
import './profile/all';
|
||||
import './datasources/settings/HttpSettingsCtrl';
|
||||
import './datasources/settings/TlsAuthSettingsCtrl';
|
||||
|
@ -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: '<?',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
coreModule.directive('folderPicker', folderPicker);
|
@ -8,7 +8,9 @@ import * as api from 'app/features/manage-dashboards/state/actions';
|
||||
jest.mock('app/features/plugins/datasource_srv', () => ({}));
|
||||
jest.mock('app/features/expressions/ExpressionDatasource', () => ({}));
|
||||
jest.mock('app/features/manage-dashboards/services/ValidationSrv', () => ({
|
||||
validateNewDashboardName: () => true,
|
||||
validationSrv: {
|
||||
validateNewDashboardName: () => true,
|
||||
},
|
||||
}));
|
||||
|
||||
jest.spyOn(api, 'searchFolders').mockResolvedValue([]);
|
||||
|
@ -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;
|
||||
|
@ -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'),
|
||||
|
@ -1 +0,0 @@
|
||||
export { uploadDashboardDirective } from './uploadDashboardDirective';
|
@ -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 = `
|
||||
<input type="file" id="dashupload" name="dashupload" class="hide" onchange="angular.element(this).scope().file_selected"/>
|
||||
<label class="btn btn-primary" for="dashupload">
|
||||
{{btnText}}
|
||||
</label>
|
||||
`;
|
||||
|
||||
/** @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);
|
@ -1,5 +0,0 @@
|
||||
// Services
|
||||
export { ValidationSrv } from './services/ValidationSrv';
|
||||
|
||||
// Components
|
||||
export * from './components/UploadDashboard';
|
@ -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();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import validationSrv from '../services/ValidationSrv';
|
||||
import { validationSrv } from '../services/ValidationSrv';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
|
||||
export const validateDashboardJson = (json: string) => {
|
||||
|
@ -1,3 +1 @@
|
||||
import './datasource_srv';
|
||||
import './plugin_component';
|
||||
import './variableQueryEditorLoader';
|
||||
|
@ -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(<Component {...props} />, elem[0]);
|
||||
scope.$on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(elem[0]);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
coreModule.directive('variableQueryEditorLoader', variableQueryEditorLoader);
|
Loading…
Reference in New Issue
Block a user