mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
* Performance: Standardize lodash imports to use destructured members Changes lodash imports of the form `import x from 'lodash/x'` to `import { x } from 'lodash'` to reduce bundle size. * Remove unnecessary _ import from Graph component * Enforce lodash import style * Fix remaining lodash imports
164 lines
4.4 KiB
TypeScript
164 lines
4.4 KiB
TypeScript
import { map, find, forEach, sortBy } from 'lodash';
|
|
import $ from 'jquery';
|
|
// @ts-ignore
|
|
import Drop from 'tether-drop';
|
|
import coreModule from 'app/core/core_module';
|
|
import { FuncDef } from './gfunc';
|
|
|
|
/** @ngInject */
|
|
export function graphiteAddFunc($compile: any) {
|
|
const inputTemplate =
|
|
'<input type="text"' + ' class="gf-form-input"' + ' spellcheck="false" style="display:none"></input>';
|
|
|
|
const buttonTemplate =
|
|
'<a class="gf-form-label dropdown-toggle"' +
|
|
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
|
|
'<icon name="\'plus\'" size="\'sm\'"></name></a>';
|
|
|
|
return {
|
|
link: function ($scope: any, elem: JQuery) {
|
|
const ctrl = $scope.ctrl;
|
|
|
|
const $input = $(inputTemplate);
|
|
const $button = $(buttonTemplate);
|
|
|
|
$input.appendTo(elem);
|
|
$button.appendTo(elem);
|
|
|
|
ctrl.datasource.getFuncDefs().then((funcDefs: FuncDef[]) => {
|
|
const allFunctions = map(funcDefs, 'name').sort();
|
|
|
|
$scope.functionMenu = createFunctionDropDownMenu(funcDefs);
|
|
|
|
$input.attr('data-provide', 'typeahead');
|
|
$input.typeahead({
|
|
source: allFunctions,
|
|
minLength: 1,
|
|
items: 10,
|
|
updater: (value: any) => {
|
|
let funcDef: any = ctrl.datasource.getFuncDef(value);
|
|
if (!funcDef) {
|
|
// try find close match
|
|
value = value.toLowerCase();
|
|
funcDef = find(allFunctions, (funcName) => {
|
|
return funcName.toLowerCase().indexOf(value) === 0;
|
|
});
|
|
|
|
if (!funcDef) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
$scope.$apply(() => {
|
|
ctrl.addFunction(funcDef);
|
|
});
|
|
|
|
$input.trigger('blur');
|
|
return '';
|
|
},
|
|
});
|
|
|
|
$button.click(() => {
|
|
$button.hide();
|
|
$input.show();
|
|
$input.focus();
|
|
});
|
|
|
|
$input.keyup(() => {
|
|
elem.toggleClass('open', $input.val() === '');
|
|
});
|
|
|
|
$input.blur(() => {
|
|
// clicking the function dropdown menu won't
|
|
// work if you remove class at once
|
|
setTimeout(() => {
|
|
$input.val('');
|
|
$input.hide();
|
|
$button.show();
|
|
elem.removeClass('open');
|
|
}, 200);
|
|
});
|
|
|
|
$compile(elem.contents())($scope);
|
|
});
|
|
|
|
let drop: any;
|
|
const cleanUpDrop = () => {
|
|
if (drop) {
|
|
drop.destroy();
|
|
drop = null;
|
|
}
|
|
};
|
|
|
|
$(elem)
|
|
.on('mouseenter', 'ul.dropdown-menu li', async () => {
|
|
cleanUpDrop();
|
|
|
|
let funcDef;
|
|
try {
|
|
funcDef = ctrl.datasource.getFuncDef($('a', this).text());
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
|
|
if (funcDef && funcDef.description) {
|
|
let shortDesc = funcDef.description;
|
|
if (shortDesc.length > 500) {
|
|
shortDesc = shortDesc.substring(0, 497) + '...';
|
|
}
|
|
|
|
const contentElement = document.createElement('div');
|
|
// @ts-ignore
|
|
const { default: rst2html } = await import(/* webpackChunkName: "rst2html" */ 'rst2html');
|
|
contentElement.innerHTML = '<h4>' + funcDef.name + '</h4>' + rst2html(shortDesc);
|
|
|
|
drop = new Drop({
|
|
target: this,
|
|
content: contentElement,
|
|
classes: 'drop-popover',
|
|
openOn: 'always',
|
|
tetherOptions: {
|
|
attachment: 'bottom left',
|
|
targetAttachment: 'bottom right',
|
|
},
|
|
});
|
|
}
|
|
})
|
|
.on('mouseout', 'ul.dropdown-menu li', () => {
|
|
cleanUpDrop();
|
|
});
|
|
|
|
$scope.$on('$destroy', cleanUpDrop);
|
|
},
|
|
};
|
|
}
|
|
|
|
coreModule.directive('graphiteAddFunc', graphiteAddFunc);
|
|
|
|
function createFunctionDropDownMenu(funcDefs: FuncDef[]) {
|
|
const categories: any = {};
|
|
|
|
forEach(funcDefs, (funcDef) => {
|
|
if (!funcDef.category) {
|
|
return;
|
|
}
|
|
if (!categories[funcDef.category]) {
|
|
categories[funcDef.category] = [];
|
|
}
|
|
categories[funcDef.category].push({
|
|
text: funcDef.name,
|
|
click: "ctrl.addFunction('" + funcDef.name + "')",
|
|
});
|
|
});
|
|
|
|
return sortBy(
|
|
map(categories, (submenu, category) => {
|
|
return {
|
|
text: category,
|
|
submenu: sortBy(submenu, 'text'),
|
|
};
|
|
}),
|
|
'text'
|
|
);
|
|
}
|