Buildfire: Private Portal plugin - buildfire

I am having a very specific issue with a gateway plugin I am trying to finish.
I am trying to navigate to a different plugin using
'buildfire.pluginInstance.get($scope.deepLinnk,function (err, plugin) {
if (err) {
$scope.status = 'error!';
}
else {
console.log(plugin);
$scope.navigateSignIn(plugin);}
});
$scope.navigateSignIn = function (plugin) {
buildfire.navigation.navigateTo({
pluginId: plugin.token,
instanceId: plugin.instanceId,
title: plugin.title,
folderName: plugin.pluginTypeId
});
};
The navigateTo object is the only way I can get buildfire.navigate.navigateTo to work for buildfire made plugins.
However, when I try to navigate to plugins that I have created, the debugger shows and an alert saying "cannot load config file" then the entire platform crashes and makes me sign in again.
How can I navigate to plugins that I have created?

How are you getting the pluginId, instanceId and folderName? You cant simply save them or hard code them in. You need to initiate a dynamic data lookup see https://github.com/BuildFire/sdk/wiki/How-to-use-the-Datastore-Dynamic-Data
also you can look at an example such as the folder plugin https://github.com/BuildFire/folderPlugin/blob/d84551feb06cfc304c325480ca96d87795a66929/widget/widget.controller.js#L163
Basically every time a plugin is updated the plugin identifiers like folderName or title may change. So you need to keep your reference data fresh using dynamic data.
Here is a simple example that may draw a better picture. If you are referencing a plugin titled "Holiday Sales" so you save to your datastore collection {title: "Holiday Sales"} and hence forth refer to it by that title. This may work for a short period of time. However, if the app owner changes the title to "Summer Sale" now your copy is out-of-date. In traditional databases you would have 2 tables one with the source of truth and the other would have a foreign key referencing the first table. This way you join and always display the latest data.
Dynamic data is sort of an assisted lookup for you. You simply give it a key and what that key references. Then at run time when you make the call it will make the lookup you need server side and return to you the latest data you are looking for.
sample:
buildfire.datastore.save("MyData",{
_buildfire: { /// key identifier
myPluginsToNavTo: {
data:["123123-123123","asdasda-asdasd"] /// plugin instances
,dataType: "pluginInstance"
}
}
});
======
buildfire.datastore.getWithDynamicData("MyData",function(err,data){
// data would be:
/*
_buildfire: { /// key identifier
myPluginsToNavTo: {
data:["55f71347d06b61b4010351dc","asdasda-asdasd"]
,dataType: "pluginInstance"
,result: [ /// <=============new property added dynamically
{
"id": "55f71347d06b61b4010351dc",
"data": {
"pluginTypeId": 3212,
"token": "6372b101-addf-45da-bb0a-9208a09e7b6b",
"title": "YouTube Plugin",
"iconUrl": "http://s3-us-west-2.amazonaws.com/pluginserver/plugins/6372b101-addf-45da-bb0a-9208a09e7b6b/resources/image.png",
}
,{
"id": "asdasda-asdasd",
"data": {
"pluginTypeId": 123123,
"token": "1223123123-addf-45da-bb0a-9208a09e7b6b",
"title": "Plugin 2",
"iconUrl": "...",
}
}
}
]
}
}
*/
});
hope this helps

Related

Get exception details from Azure Monitor Workbook that deals with multiple app insight instances

I am working on creating a workbook that provides an umbrella view over multiple app insight instances. Our solution has many microservices (Azure functions) each having its own app insight instance. Aim of this workbook is to provide a health status for the whole app by surfacing up errors across app insight instances in to a single view.
I have used the "Failure Analysis" template to set this up. User is able to select different app insight instances at the top and the views will filter based on that. There's a view that shows exception counts with trends like this. Each error may belong to different App Insight instances.
When you click on a line item all instances of that error will be shown in a following view like this
I use the following query to load it
let row = dynamic({Row});
let req = requests
| where '{Row}' == '{}' or (row.Kind == 'Application' and row.Id
== appName) or (row.Kind == 'Request' and row.Id ==
strcat(appName, "::", name))
| where success == "False";
let errors = exceptions
| where appName == appName
| where timestamp between({TimeRange:start}..{TimeRange:end});
errors
| join req on operation_Id
| project operation_Id, itemId, timestamp,requestName=name,
exception=type, method, outerMessage, innermostMessage,
details, appName
As mentioned in this question Get exception details from a Azure Monitor Workbook, the itemId is available and I try to link it to the "Exception Details" view. Please note that these errors can come from one of many App Insight instances based on what gets selected at the previous view.
I have configured the item Id and appName columns as follows using Link renderer and Automatic renderer.
However the link always directs to one specific app insight instance (Not the one associated with the error) and hence the error won't get loaded. Is it possible to load the "Detail Views" across App Insight instances using this technique? If not what could be other avenues?
When the application insights is workspace based, each telemetry item has a field _ResourceId that contains a link to the resource, for example
/subscriptions/c8vfbeab-a5a67-4272-aa6e-4c9f4142e962/resourcegroups/rg-my-resource-group/providers/microsoft.insights/components/my-ai-resource
You can use this a part of the url to create a deep link to the details page of the Application Insights resource of the telemetry with the specified item id. Take this query for example:
exceptions
| take 1
| extend portalUrl = strcat("https://portal.azure.com/#blade/AppInsightsExtension/BladeRedirect/BladeName/searchV1/ResourceId/", url_encode(_ResourceId), "/BladeInputs/%7B%22tables%22%3A%5B%22availabilityResults%22%2C%22requests%22%2C%22exceptions%22%2C%22pageViews%22%2C%22traces%22%2C%22customEvents%22%2C%22dependencies%22%5D%2C%22timeContextWhereClause%22%3A%22%7C%20where%20timestamp%20%3E%20datetime(%5C%222022-02-12T12%3A55%3A02.739Z%5C%22)%20and%20timestamp%20%3C%20datetime(%5C%222022-03-14T12%3A55%3A02.739Z%5C%22)%22%2C%22filterWhereClause%22%3A%22%7C%20where%20*%20has%20%5C%22a1a20ad1a12ff348a852288a4d9953a5%5C%22%7C%20order%20by%20timestamp%20desc%22%2C%22originalParams%22%3A%7B%22eventTypes%22%3A%5B%7B%22value%22%3A%22availabilityResult%22%2C%22tableName%22%3A%22availabilityResults%22%2C%22label%22%3A%22Availability%22%7D%2C%7B%22value%22%3A%22request%22%2C%22tableName%22%3A%22requests%22%2C%22label%22%3A%22Request%22%7D%2C%7B%22value%22%3A%22exception%22%2C%22tableName%22%3A%22exceptions%22%2C%22label%22%3A%22Exception%22%7D%2C%7B%22value%22%3A%22pageView%22%2C%22tableName%22%3A%22pageViews%22%2C%22label%22%3A%22Page%20View%22%7D%2C%7B%22value%22%3A%22trace%22%2C%22tableName%22%3A%22traces%22%2C%22label%22%3A%22Trace%22%7D%2C%7B%22value%22%3A%22customEvent%22%2C%22tableName%22%3A%22customEvents%22%2C%22label%22%3A%22Custom%20Event%22%7D%2C%7B%22value%22%3A%22dependency%22%2C%22tableName%22%3A%22dependencies%22%2C%22label%22%3A%22Dependency%22%7D%5D%2C%22timeContext%22%3A%7B%22durationMs%22%3A2592000000%7D%2C%22filter%22%3A%5B%5D%2C%22searchPhrase%22%3A%7B%22originalPhrase%22%3A%22", itemId,"%22%2C%22_tokens%22%3A%5B%7B%22conjunction%22%3A%22and%22%2C%22value%22%3A%22a1a20ad1a12ff348a852288a4d9953a5%22%2C%22isNot%22%3Afalse%2C%22kql%22%3A%22%20*%20has%20%5C%22a1a20ad1a12ff348a852288a4d9953a5%5C%22%22%7D%5D%7D%2C%22sort%22%3A%22desc%22%7D%7D")
| project timestamp, problemId, itemId, portalUrl
If you create a workbook and render a table based on the query above you have to modify the itemId column to be a link like this:
Clicking the itemId column it should open the correct Application Insights resource details page:
Now, I hope this give you enough clues to extend your own queries by including the deep link url in your query output.
For completeness, this is the full workbook Gallery Template:
{
"version": "Notebook/1.0",
"items": [
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "exceptions\n| take 1\n| extend portalUrl = strcat(\"https://portal.azure.com/#blade/AppInsightsExtension/BladeRedirect/BladeName/searchV1/ResourceId/\", url_encode(_ResourceId), \"/BladeInputs/%7B%22tables%22%3A%5B%22availabilityResults%22%2C%22requests%22%2C%22exceptions%22%2C%22pageViews%22%2C%22traces%22%2C%22customEvents%22%2C%22dependencies%22%5D%2C%22timeContextWhereClause%22%3A%22%7C%20where%20timestamp%20%3E%20datetime(%5C%222022-02-12T12%3A55%3A02.739Z%5C%22)%20and%20timestamp%20%3C%20datetime(%5C%222022-03-14T12%3A55%3A02.739Z%5C%22)%22%2C%22filterWhereClause%22%3A%22%7C%20where%20*%20has%20%5C%22a1a20ad1a12ff348a852288a4d9953a5%5C%22%7C%20order%20by%20timestamp%20desc%22%2C%22originalParams%22%3A%7B%22eventTypes%22%3A%5B%7B%22value%22%3A%22availabilityResult%22%2C%22tableName%22%3A%22availabilityResults%22%2C%22label%22%3A%22Availability%22%7D%2C%7B%22value%22%3A%22request%22%2C%22tableName%22%3A%22requests%22%2C%22label%22%3A%22Request%22%7D%2C%7B%22value%22%3A%22exception%22%2C%22tableName%22%3A%22exceptions%22%2C%22label%22%3A%22Exception%22%7D%2C%7B%22value%22%3A%22pageView%22%2C%22tableName%22%3A%22pageViews%22%2C%22label%22%3A%22Page%20View%22%7D%2C%7B%22value%22%3A%22trace%22%2C%22tableName%22%3A%22traces%22%2C%22label%22%3A%22Trace%22%7D%2C%7B%22value%22%3A%22customEvent%22%2C%22tableName%22%3A%22customEvents%22%2C%22label%22%3A%22Custom%20Event%22%7D%2C%7B%22value%22%3A%22dependency%22%2C%22tableName%22%3A%22dependencies%22%2C%22label%22%3A%22Dependency%22%7D%5D%2C%22timeContext%22%3A%7B%22durationMs%22%3A2592000000%7D%2C%22filter%22%3A%5B%5D%2C%22searchPhrase%22%3A%7B%22originalPhrase%22%3A%22\", itemId,\"%22%2C%22_tokens%22%3A%5B%7B%22conjunction%22%3A%22and%22%2C%22value%22%3A%22a1a20ad1a12ff348a852288a4d9953a5%22%2C%22isNot%22%3Afalse%2C%22kql%22%3A%22%20*%20has%20%5C%22a1a20ad1a12ff348a852288a4d9953a5%5C%22%22%7D%5D%7D%2C%22sort%22%3A%22desc%22%7D%7D\")\n| project timestamp, problemId, itemId, portalUrl",
"size": 1,
"timeContext": {
"durationMs": 86400000
},
"queryType": 0,
"resourceType": "microsoft.insights/components",
"gridSettings": {
"formatters": [
{
"columnMatch": "problemId",
"formatter": 1,
"formatOptions": {
"linkColumn": "portalUrl",
"linkTarget": "Url"
}
}
]
}
},
"name": "query - 2"
}
],
"fallbackResourceIds": [
"/subscriptions/4547474-1a67-4272-aa6e-4c9f4142e269/resourceGroups/rg-resourcegroup-prod/providers/microsoft.insights/components/appi-demo-prod"
],
"$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json"
}
It looks like from a quick perusal of the code, that if you also have an appName column in the row where itemId is, it will try to look in the resource list used in the query to try to find a resource with that same name, and if not, just take the first one it can find?
but i see that you have appName there, but i'm not sure the rest of the configuration from your step? are you also using all of the resources in the query?

Read user entered input in blockly block

I have the below code in my blockly.js file
Blockly.Blocks['account_number'] = {
// Other type.
init: function() {
this.jsonInit({
"message0": "account_number %1",
"args0": [{"type": "field_input", "name": "TYPE", "text": ""}],
"output": "Type",
"colour": 320,
"tooltip": "Custom type to allow.",
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=702"
});
}
};
I am using this in my index.html as follows
<category name="sender" colour="%{BKY_MATH_HUE}">
<block type="account_number" name="accnum"></block>
</category>
How can I get the user entered number in the account number block in this js file?
The short answer:
Blockly.JavaScript['account_number'] = function(block) {
var code = block.getFieldValue('TYPE');
return code;
}
(You appear to have named your field "TYPE", by the way - are you entirely sure that's what you want to name it?)
The medium answer: include the above, and generate the JavaScript for your workspace by getting your workspace and using:
var generatedCode = Blockly.JavaScript.workspaceToCode(workspace);
in wherever you are trying to generate your JavaScript.
The long answer is that if that isn't enough to get you started, I'll need to see a bit more about how you're trying to generate your code and what you're going to do with it.
These links may also be helpful, if you haven't checked them out already:
https://developers.google.com/blockly/guides/configure/web/custom-blocks#add_generator_function
https://developers.google.com/blockly/guides/create-custom-blocks/generating-code

jquery jtable deleteConfirmation function not working

I am trying to use the deleteConfimation function option but I find that the default confirmation box pops up before I even get into the deleteConfimation function - what am I missing?
In the code below I can set break points and watch the data object being set up correctly with its new defaultConfirmMessage, but the basic jtable default delete confirmation box has already appeared and I never see an altered one.
$(container).jtable({
title: tablename,
paging: true,
pageSize: 100,
sorting: true,
defaultSorting: sortvar + ' ASC',
selecting: false,
deleteConfirmation: function(data) {
var defaultMessage = 'This record will be deleted - along with all its assignments!<br>Are you sure?';
if(data.record.Item) { // deleting an item
// Check whether item is in any preset lists
var url = 'CampingTablesData.php?action=CheckPresets&Table=items';
$.when(
ReturnAjax(url, {'ID':data.record.ID}, MyError)
).done(
function(retdata, status) {
if(status=='success') {
if(retdata.PresetList) {
data.deleteConfirmMessage = 'Item is in the following lists: ' + retdata.PresetList + 'Do you still want to delete it?';
}
} else {
data.cancel = true;
data.cancelMessage = retdata.Message;
}
}
);
} else {
data.deleteConfirmMessage = defaultMessage;
}
},
messages: {
addNewRecord: 'Add new',
deleteText: deleteTxt
},
actions: {
listAction: function(postData, jtParams) {
<list action code>
},
createAction: function(postData) {
<create action code>
},
updateAction: 'CampingTablesData.php?action=update&Table=' + tablename,
deleteAction: 'CampingTablesData.php?action=delete&Table=' + tablename
},
fields: tableFields --- preset variable
});
==========
After further testing the problem is only when deleting an item and it goes through the $.when().done() section of code. The Ajax call to the deletion url does not wait for this to complete - how do I overcome this?
i don't think you can get your design to work. What does the A in ajax stand for? Asynchronous! Synchronous Ajax has been deprecated for all sorts of good design and performance reasons.
You need to design you application to function asynchronously. Looking at your code, it feels you are misusing the deleteConfirmation event.
Consider changing the default deleteConfirmation message to inform the user, that the delete might not succeed if certain condition are met. Say
messages: {
deleteConfirmation: "This record will be deleted - along with all its assignments, unless in a preset list. Do you wish to try to delete this record?"
},
Then on the server, check the preset lists, and if not deletable, return an error message for jTable to display.
Depending on how dynamic your preset lists are, another approach might be to let the list function return an additional flag or code indicating which, if any, preset lists the item is already in, then your confirmation function can check this flag / indicator without further access to the server.
Thanks to MisterP for his observation and suggestions. I also considered his last approach but ended up setting deleteConfirmation to false (so as not to generate a system prompt) then writing a delete function that did not actually delete, but returned the information I needed to construct my own deleteConfimation message. Then a simple if confirm(myMessage) go ahead and delete with another Ajax call.

Chrome DevTools Protocol: control new tabs

Need to be done: I need to simulate user interactions (journeys) across a chain of sites.
Question: Do you have any tips how to programatically controll a tab opened as a result of a simulated click?
My experience:
I'm using the chrome-remote-interface npm package.
I'm able to simulate a click with a custom ChromeController class which initializes the chrome-remote-interface and these methods:
async simulateClick(selector) {
return await this.evaluate(function (selector) {
document.querySelector(selector).click()
}, selector);
}
/**
* Shamelessly stolen from simple-headless-browser
*/
async evaluate (fn, ...args) {
const exp = args && args.length > 0 ? `(${String(fn)}).apply(null, ${JSON.stringify(args)})` : `(${String(fn)}).apply(null)`
const result = await this.client.Runtime.evaluate({
expression: exp,
returnByValue: true
})
return result
}
Now I would like to interact with the recently opened tab. I can get the targetId of the new tab with the experimenetal Target Domain (prototyping in node cli):
var targets;
chromeController.client.Target.getTargets().then(t => targets = t);
Which results in:
{ targetInfos:
[ { targetId: '97556479-cdb6-415c-97a1-6efa4e00b281',
type: 'page',
title: 'xxx/preview/239402/',
url: 'xxx/preview/239402/' },
{ targetId: 'bbfe11d5-8e4a-4879-9081-10bb7234209c',
type: 'page',
title: 'Document',
url: 'xxx/preview/239402/teaser/0/' } ] }
I am able to switch between the tabs with:
chromeController.client.Target.activateTarget({targetId:'xxx'})
However I'm not able to get any interaction with this, I can't find the connection, how to load it into the Page and Runtime objects.
I've searched in the docs and also tried googling: 'site:chromedevtools.github.io targetId' which only lead me to
> chromeController.client.Browser.getWindowForTarget({targetId: '97556479-cdb6-415c-97a1-6efa4e00b281'}).catch(e => console.log(e.message));
Promise { <pending> }
> 'Browser.getWindowForTarget' wasn't found
I've also tried to Target.setDiscoverTargets({discover: true}) and to close the original tab.
Thanks for any help!
Recently faced this same issue and in short I had to create a new dev tools protocol client for each new target I wanted control over.
My experience is with dev tools protocol using direct communication with websocket but the api is the same so it should be similar. So here is a summary of what I had to do.
Initially looking at the docs I would have assumed Target.attachToTarget should give us control of the new tab but I found that it didn't work.
My workaround was to create a listener that listened for the Target.targetCreated event which provides a targetInfos just like you found with Target.getTargets but for every new target created like a new tab, page, or iframe. Note: you need to enable Target.setDiscoverTargets in order to receive these events over the protocol.
[ { targetId: '97556479-cdb6-415c-97a1-6efa4e00b281',
type: 'page',
title: 'xxx/preview/239402/',
url: 'xxx/preview/239402/' },
{ targetId: 'bbfe11d5-8e4a-4879-9081-10bb7234209c',
type: 'page',
title: 'Document',
url: 'xxx/preview/239402/teaser/0/' } ] }
With that listener I looked for targets that were of type page, you could filter on a specific url if you know what the page will be. With the targetId in hand I requested available websocket targets following the HTTPEndpoints section near the bottom of the devtools home page.
GET /json or /json/list
A list of all available websocket targets.
[ {
"description": "",
"devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:9222/devtools/page/DAB7FB6187B554E10B0BD18821265734",
"id": "DAB7FB6187B554E10B0BD18821265734",
"title": "Yahoo",
"type": "page",
"url": "https://www.yahoo.com/",
"webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/DAB7FB6187B554E10B0BD18821265734"
} ]
I could then launch a new dev tools protocol client using the webSocketDebuggerUrl and have full control over the tab.
I know this is a pretty round about way but, its the only way I was able to make if work.
Although these days it's probably easier to use something like puppeteer to interface with multiple tabs in chrome if you can. Here is the source code to a puppeteer module that follows new tabs that could be good reference for trying to replicate it pageVideoStreamCollector.ts
This is a very late answer but just putting this here if anyone else has the same issue as help on chrome dev tools is very hard to come by. Hope it helps someone out.
I also am getting "Browser.getWindowForTarget wasn't found" on debian, google-chrome-unstable version 61

how to get "my pull requests" from github api?

If you look at: http://developer.github.com/v3/pulls/ it shows you how to get pull requests for a given repository.
How do we get "my pull requests" from the GitHub API similar to the data displayed on the GitHub dashboard?
I asked Github directly. A rep told me to use the search endpoint. Search for issues owned by you that are open and of type pr.
https://api.github.com/search/issues?q=state%3Aopen+author%3Adavidxia+type%3Apr
If you're using a python client lib like Pygithub you can do
issues = gh.search_issues('', state='open', author='davidxia', type='pr')
You can also use GraphQL API v4 to get all your pull requests :
{
user(login: "bertrandmartel") {
pullRequests(first: 100, states: OPEN) {
totalCount
nodes {
createdAt
number
title
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
Try it in the explorer
or using viewer :
{
viewer {
pullRequests(first: 100, states: OPEN) {
totalCount
nodes {
createdAt
number
title
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
First you have to realize that you must authenticate using either Basic Authentication or a token. Next you have to realize that there is no simple way to do this so you will have to be clever.
To be specific, if you probe https://api.github.com/issues, you'll notice that the issues there have a hash called pull_request which should have 3 URLs: html, diff, and patch. All three will be non-null if the issue is also a Pull Request. (Pro-tip: They're the same thing as far as GitHub is concerned…sort of.)
If you iterate over your issues and filter for ones where those attributes are not null, then you'll have your pull requests.

Resources