How to make Grafana's datasource plugin compliant with Query Inspector? - plugins

I'm developping a datasource plugin for Grafana that works nicely but if I try to use the Query Inspector, I only get the following message "Loading query inspector... ".
So how to make my plugin compliant with this feature? Is there any specific function to add to my datasource.ts file ?
[edit]
I'm using Grafana 6.7.1 and #grafana/toolkit
Thanks for your help

Finally , I think I understood how it works.
The query inspector is triggered only if an event (dsRequestResponse or dsRequestError) is emitted after the query is done by the backend server (see code documentation)
For example :
import { getBackendSrv } from '#grafana/runtime';
//later in your code
getBackendSrv().datasourceRequest({
url:'https://api.github.com/repos/grafana/grafana/stats/commit_activity',
method:'GET'
}).then((data: any) => console.log('DATA',data));
In my datasource, I'm doing fetch() call from the browser so no event is emitted and then no data are displayed in the query inspector. But here is a workaround to emit the event :
import { SystemJS } from '#grafana/runtime'
//later in your code
SystemJS.load('app/core/app_events').then((appEvents:any) => {
appEvents.emit('ds-request-response', data) // where data is the data to display
})
I hope it can help someone else

Related

"Import" doesn't work on the spec file on Cypress

If someone could help me on this please.
I have created page objects with the following code:
class Login {
username(){
return cy.get('#UserName').type('test1')
}
password(){
return cy.get('#password-field').type('test2')
}
loginbtn(){
return cy.get('.btn').click()
}
}
export default Login
Here I have created class Login and imported on the spec file as:
import Login from '../support/PageObjects/Login'
beforeEach('Login to shipment page',() => {
cy.Login()
})
This was working before but now this is not working and I get the error (on hover) telling "Login is declared but it's value is never read." I have changed nothing. I am facing this issue many times but never got the proper solution for this.
The login is not needed to be imported when you have a custom command like cy.Login().
That is why the error occurs:
'Login' is declared but it's value is never read.
Custom commands are global to all tests and never need importing. The Login page is being added to the tests via cy.Login() and you can remove the import without affecting it.
This has to be something to do with your custom command cy.Login(), I imagine the code for it to be something like below:
// cypress/support/commands.js
const login = new require('../PageObjects/Login.js')
Cypress.Commands.add('Login', () => {
login.username()
login.password()
login.loginbtn()
})
Now that of course needs to be imported into cypress/support/e2e.js, but that is the default - check it anyway.
// cypress/support/e2e.js
import './commands.js'
If you are using the Typescript, options are similar.
By the way, what is the file you are having the error from? I suspect that will give a clue.
You have to create an object of the class Login and using that you can access the different methods. So your code should look like this:
import Login from '../support/PageObjects/Login'
const login = new Login()
beforeEach('Login to shipment page', () => {
login.username()
login.password()
login.loginbtn()
})

Custom Maui Handler control creates handler when used in xaml but when created with c# does not create the handler

The repro is a small example based on the maui template.
I created a button called MyButtonView and changed the MainPage to consume that control.
The button is created and shows correctly on the page, but when I try to create just the control as in
var b = new MyButtonView(); the handler is not created and I cant figure out how to get this created.
Notice in the source I have implemented the clicked event to show how the handler is not created. I am sure I am missing something but could someone lead me in the right direction?
Github repro
So it seems that if the control once created has a null handler, you will need to call MyButtonView.ToHandler(mauiContext); sounds simple, but getting the mauiContext is a bit of a pain.
The only way i was able to do this was to do the following in the MauiProgram.cs. This works for windows, have yet to try it with iOS
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler<DtNavigationView, DtNavigationViewHandler>();
handlers.AddHandler<DtWindowTabView, DtWindowTabViewHandler>();
handlers.AddHandler<DtWindowTabItem, DtWindowTabItemHandler>();
});
builder.UseMauiEmbedding<Application>();
var mauiapp = builder.Build();
mauiContext = new MauiContext(mauiapp.Services);
return mauiapp;
Now you can use the static context to get the object to a handler, by using
MyButtonView.ToHandler(MauiProgram.mauiContext);
Dont think this is the best way to do this but its all i can come up with for now.
Update - this is not the answer to the issue. Storing the MauiContext at this point will result in other issues such as not being able to have the base navigation framework setup.
So the only work around i have found so far that will work for me is to capture the MauiContext was to save it off in the handler when
public override void SetMauiContext(IMauiContext mauiContext) { DtMauiContext.mauiContext = mauiContext; base.SetMauiContext(mauiContext); }
The DtMauiContext is a static i can use it in the view level.
In the Maui source they have Application.Current.FindMauiContext(), it would have been so easy of they just exposed this.

How to avoid errors from onchange methods on lightning-input?

I'm trying to learn the basics of Lightning Web Components and I'm having trouble getting the value of a lighting-input element.
I understand that it's designed for one way data binding instead of two way (a decision that I find questionable), but I can't get an onchange method to work either. I'm running this sample on the Lighting playground:
//app.html
<lightning-input
label="test"
onchange={handleChange}>
</lightning-input>
//app.js
import { LightningElement, track, api } from 'lwc';
export default class App extends LightningElement {
handleChange(event) {
console.log(event)
}
}
And making any change to the input in the template gives me the following error:
Error: Disallowed method "appendChild" in ShadowRoot.
Why does the onchange method not work as expected and should I go about making it work as intended?
console.log() works in playground.
You have to write this way - console.log(event.target.value)
Replace it in your code & it will print values..!!
Turns out the problem was with using console.log(). Seems that it has some issues working in the Playground.

CKEditor: how to remove a plugin that has been added?

I'm just beginning to use CKEditor, but have a hard time understanding the plugins system.
I was able to add a simple button that says 'Test' when you click on it with :
var myplugin_function = function () {
alert('Test');
}
var plugin_name='myplugin';
CKEDITOR.plugins.add(plugin_name,
{
init:function(c) {
c.addCommand(plugin_name,myplugin_function);
c.ui.addButton(plugin_name,
{
label:'This is my plugin',
command:plugin_name,
icon:this.path+'myplugin.png'
});
}
});
I know this code should be executed only once, for example in a plugin.js, but that's not how I use it. The CKEditor instance, including my plugin code is executed each time the Ajax-page is loaded.
That's why I use this to remove the instance, if it exists :
if (CKEDITOR.instances['mytextarea']) {
CKEDITOR.remove(CKEDITOR.instances['mytextarea']);
}
Then I use the jquery way to create the ckeditor from a textarea:
$('#mytextarea').ckeditor();
But the 2nd time the ajax-page loads, I get an error about the plugin already being registered. So I need a way to remove the plugin and be able to add it again.
Is this even possible?
UPDATE
This seems to work :
I now check if the plugin is already registered with :
if (!CKEDITOR.plugins.registered[plugin_name]) {
}
around the CKEDITOR.plugins.add(b, ... part
You are not showing how you are adding the plugin, so it's hard to tell what's your exact problem; but from the code that you have provided I can suggest that you use variable names better than "a", "b" and "c". It's quite harder to understand the code this way.
Also, CKEDITOR.remove just removes the instance from the instances array, but it doesn't really clear the used resources, you should use CKEDITOR.instances['mytextarea'].destroy( true ) instead

MVC2 sending collections from the view a controller via json

I've been looking on forums for 2 days now and can't find a good answer so I'll just post it.
I appear to be having a problem posting JSON back to the controller to save. The JSON should map to model view but it keeps getting default(constructor)values rather then the values from the POST.
We have a series of JS widgets that contain a data field with json in them. We do all our data manipulation in these widget objects on the client side. When a user wants to save we grab the data we need from the widgets involved and we put it into another JSON object that matches a ViewModel and POST that back to the server.
For example:
$("#Save").click(function () {
if (itemDetails.preparedForSubmit() && itemConnections.preparedForSubmit()) {
itemComposite.data.Details = itemDetails.data;
itemComposite.data.Connections= itemConnections.data;
$.post(MYURL, itemComposite.data);
} else {
alert("failed to save");
}
});
The preparedForSubmit() method simple does stuff like any validation checks or last minute formatting you might need to do client side.
The itemDetails widgets data matches a ViewModel.
The itemConnections widgets data matches a collection of ViewModels.
The Controller looks like this:
[HttpPost]
virtual public JsonResult SaveItemDetailsComposite(ItemComposite inItemData)
{
if (ModelState.IsValid)
{
try
{
_Mapper.Save(itemComposite.Details , itemComposite.Connections);
return Json(true);
}
catch (Exception ex)
{
_log.Error("Exception " + ex.InnerException.Message);
throw;
}
}
return Json(SiteMasterUtilities.CreateValidationErrorResponse(ModelState));
}
The ItemComposite Class is a simple View Model that contains a single itemDetails object and a collection of itemConnections. When it returns data to here it is just getting the default data as if it got a new ItemComposite rather than converting the POST data.
in Firebug I see the data is posted. Although it looks weird not automatically formatted in firebug.
Are you saying that itemComposite.data is formatted as a JSON object? If so, I'm pretty sure you're going to have to de-serialize it before you can cast it to your object. Something like:
ItemComposite ic = jsSerializer.Deserialize<ItemComposite>(this.HttpContext.Request.Params[0]);
You may want to look into a framework like JSON.NET to ensure that your data is being serialized properly when it gets supplied to your Action.
JSON.NET seems like it's one of the main stream frameworks: http://json.codeplex.com/releases/view/43775
Hope this helps.
Cory
You could also use the JSON Serializer in WCF: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.datacontractjsonserializer.aspx
SO wouldn't let me put both links in one answer, sorry for the split answer.
Thanks everyone. I think I have solved my problem and I'm pretty sure that I had four issues. For the most part I followed thatSteveguys's suggestion and read more on this article: http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx
Using jQuery's post() method and specifying json as the type didn't seem to actually send it as json. By using the ajax() method and specifying json it sent it as json.
The JSON.serialize() method was also need to cleanly send over the json.
Also my ViewModel design was a big problem. We are using the MS code analytic build junk and it didn't want me having a setter for my collections in the ViewModel. So me being from a java/hibernate world, thought it didn't need them to bind and it would just come in as a serialized object magically. Once I just suppressed the error and reset up my setters. I am getting the collections now in my controller.
I believe using the MVC2 Future's Value Providers are doing something but it still doesn't convert json dates robustly, So I am still investigating the best way to do that.
I hope my issues help out others.
UPDATE: using this method to update collections of data appears to be super slow. A collection with 200 entries in it and 8 fields per entry takes 3 minutes to get to the controller. Just 1 or 2 entries take very little time. The only thing I know of that is happening between here is data binding to the model view. I don't know if MVC2 provides a easy way to send this much data and bind it.