I am in the process of trying to create a custom HTML app in Rally to have a User Story created through the Add New component and drawing on data from an external source using JQuery with YQL JSON query.
This process works a wonder for pre-filled name, description and notes. However, the only way at the moment Owner works pre-filled is using an Object Dropdown to manually select the user. I want to be able to pull the Owner from the same external source.
Presently this is dummy code to test the theory:
var statement = "select * from html where url='" + value + "' and xpath='//h1'";
document.getElementById('statement').innerHTML = statement;
$.queryYQL(statement, "json", function (data) {
var item = data.query.results.h1;
for(var i=0;i<item.length;i++){
title = item[i].content;
style = item[i].style;
output += "<h3>"+title +"<br />"+ style +"</h3>";
}
document.getElementById('results').innerHTML = output;
});
function onAddNewPreCreate(addNew, eventArgs) {
eventArgs.item["Name"] = title;
eventArgs.item["Description"] = output;
eventArgs.item["Notes"] = style;
eventArgs.item["Owner"] = user;
}
The 'value' variable is set via a textbox where the user can input the URL of where they want to grab the external data from.
The user variable is set via the dropdown. I have tried replacing the user variable with the exact same display name as the user in Rally such as eventArgs.item["Owner"] = "User Name"; but this results in a blank for the Owner of the User Story when created.
Any ideas on how this may be achieved?
Since Users are objects in Rally, you cannot set an Artifact's Owner attribute to be the string of a Rally username, rather, you must set the Owner to be a Reference to a valid Rally User, in the form of a ref: /user/12345678910 where the long integer is the Object ID of the User of interest. You can use the rallyDataSource and AppSDK to do a query on the string value of the Rally User Name, and obtain the needed ref.
I've included a basic example that illustrates the idea of taking an e-mail formatted User Name, and querying Rally for the reference to the needed User object. The example uses a simple DOM <select> component to simulate an "external" source of username data (in your case populated via JQuery with YQL JSON). The examples does this in lieu of the AppSDK ObjectDropdown, which although the simplest way to accomplish this, as you note doesn't suit your needs since you are polling an external source as the source of your user-selector.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- Copyright (c) 2011 Rally Software Development Corp. All rights reserved -->
<html>
<head>
<title>Component Example: Add New User Story, "External" User Chooser</title>
<meta name="Name" content="Component Example: Add New User Story, 'External' User Chooser" />
<meta name="Version" content="2012.1" />
<meta name="Vendor" content="Rally Labs" />
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.26/sdk.js"></script>
<script type="text/javascript">
// Global variables to store Reference to selected User
var userRef = null;
var rallyDataSource;
var getUserRef = function(results) {
var user = results.users[0];
userRef = user._ref;
};
function userSelectChanged() {
var userChooser = document.getElementById("userChooser");
var strUser = userChooser.options[userChooser.selectedIndex].value;
queryString = '(UserName = "' + strUser + '")';
var userQueryConfig = {
type : 'user',
key : 'users',
fetch: 'UserName,DisplayName,Role',
query: queryString
};
rallyDataSource.findAll(userQueryConfig, getUserRef);
}
function onAddNewAdd(addNew, eventArgs){
var createdItem = eventArgs.item;
var createdFormattedId = createdItem.FormattedID;
alert("Created new User Story with Formatted ID: " + createdFormattedId);
}
function onAddNewPreCreate(addNew, eventArgs)
{
// Grab Rally ref of User selected in HTML dropdown
// set it as Owner attribute of created User Story
eventArgs.item["Owner"] = userRef;
}
function onLoad() {
rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
var addNewConfig = {
types : ["HierarchicalRequirement"]
};
// Populate userRef from Rally for default selected user:
userSelectChanged();
var addNew = new rally.sdk.ui.AddNewArtifact(addNewConfig, rallyDataSource);
addNew.addEventListener("onAdd",onAddNewAdd);
addNew.addEventListener('onPreCreate', onAddNewPreCreate);
addNew.display("addNewDiv");
}
rally.addOnLoad(onLoad);
</script>
</head>
<body>
<div id="addNewDiv"></div>
<div id="userChooserDiv">
Select a Rally User as Story Owner:
<select id="userChooser" onChange="userSelectChanged()">
<option selected value="user1#company.com">user1#company.com</option>
<option value="user2#company.com">user2#company.com</option>
<option value="user3#company.com">user3#company.com</option>
</select>
</body>
</html>
Related
How to retrieve a complete row from a spreadsheet based on a filter on an action such as a click of a button.
I read that GAS is server-side scripting and it is complex to gain access to a spreadsheet.
Is that so. Please guide me.
I have done till this:
$("#form-action")
.button()
.click(function() {
var ss = SpreadsheetApp.openById("");
var sheet = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(sheet.getSheetByName('Test'));
SpreadsheetApp.getActiveSheet().getRange("D1").setFormula('Query(A:C,"SELECT A,B,C WHERE B="' + "mydata'" + ',1)');
SpreadsheetApp.getActiveSheet().getRange("E:J").getValues();
});
Gaining access to the spreadsheet is not difficult at all. You have to remember that while Google Apps Script runs on Google servers, the client-side code (e.g. HTML and JavaScript code you use in your UI templates) will be sent to your browser for rendering, so you can't really mix the two and write jQuery code in GAS(.gs) files or vice versa.
To clarify, commands like
var ss = SpreadsheetApp.openById("");
must be kept in .gs files. To use client-side HTML and JavaScript, you must create separate HTML files in your project (go to File - New - HTML file). Here's more information on serving HTML in GAS https://developers.google.com/apps-script/guides/html/
Luckily, Google provides the API that allows you to communicate between client and server sides by calling 'google.script.run.' followed by the name of the function in '.gs' file.
Example function in '.gs' file
function addRow() {
var sheet = SpreadsheetApp.getActive()
.getSheets()[0];
sheet.appendRow(['Calling', 'server', 'function']);
}
In your HTML template file, here's how you would call this function
<script>
google.script.run.addRow();
</script>
Consider the example that is more relevant to your situation. In my spreadsheet, the QUERY formula changes dynamically based on the value entered by the user. The form with input field is displayed in the sidebar.
Project structure
Code for 'sidebar.html' is below. Note that using the 'name' attribute of the <input> element is mandatory. On form submit, the value of the attribute ('filterBy') will be transformed into propetry of the form object that we can reference in our server function to get user input.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js">
</script>
</head>
<body>
<form id="myForm">
<input type="text" name="filterBy">
<input type="submit" value="submit">
</form>
<table id="myTable"></table>
<script>
$('document').ready(function(){
var form = $('#myForm');
var table = $('#myTable');
var runner = google.script.run;
form.on('submit', function(event){
event.preventDefault(); //prevents <form> redirecting to another page on submit
table.empty(); // clear the table
runner.withSuccessHandler(function(array){ //this callback function will be invoked after the 'retriveValues()' function below
for (var i = 0; i < array.length; i++) {
var item = '<tr><td>' + array[i] +'</td></tr>';
table.append(item);
}
})
.retrieveValues(this); //the function that will be called first. Here, 'this' refers to the form element
});
});
</script>
</body>
</html>
Code in '.gs' file:
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheets()[0];
function onOpen() {
var ui = SpreadsheetApp.getUi();
var htmlOutput = HtmlService.createTemplateFromFile('sidebar')
.evaluate();
ui.showSidebar(htmlOutput);
}
function retrieveValues(req) {
var res = [];
var filterBy = req.filterBy; //getting the value of the input field.
sheet.getRange(1, 2, 1, 1)
.setFormula("QUERY(A1:A, \"SELECT A WHERE A > " + filterBy + "\")");
sheet.getRange(1, 2, sheet.getLastRow(), 1)
.getValues()
.map(function(value){
if (value[0] != "") res = res.concat(value[0]); // get only the values that are not empty strings.
});
return res;
}
Here's the result of entering the value and submitting the form. The server-side function returns the array of values greater than 5. The callback function that we passed as parameter to 'withSuccessHandler' then receives this array and populates the table in the sidebar.
Finally, I'm not sure why you are using the QUERY formula. Instead of modifying 'SELECT' statement, you could simply take the values from the target range an filter them in GAS.
I am working on visio in SharePoint-2013 using visio web access web part .In VWA I was able to read all the shapes and there by displaying shape text. Now Microsoft has released new javascript api . where it will take the url of the visio file and it displays Visio on click of a button named initEmbeddedframe.
Also they have given one more button, on click of which selected shape text is supposed to display.But it's coming to catch block of getSelectedShapeText() method. As I am new to sharepoint as well as Visio I need help from you guys.
would like to provide the code which need to be embed in Script editor web aprt of a sharepoint page.
<script src='https://visioonlineapi.azurewebsites.net/visio.js' type='text/javascript'></script>
Enter Visio File Url:<br/>
<script language="javascript">
document.write("<input type='text' id='fileUrl' size='120'/>");
document.write("<input type='button' value='InitEmbeddedFrame' onclick='initEmbeddedFrame()' />");
document.write("<br />");
document.write("<input type='button' value='SelectedShapeText' onclick='getSelectedShapeText()' />");
document.write("<textarea id='ResultOutput' style='width:350px;height:60px'> </textarea>");
document.write("<div id='iframeHost' />");
var textArea;
// Loads the Visio application and Initializes communication between devloper frame and Visio online frame
function initEmbeddedFrame() {
textArea = document.getElementById('ResultOutput');
var url = document.getElementById('fileUrl').value;
if (!url) {
window.alert("File URL should not be empty");
}
// APIs are enabled for EmbedView action only.
url = url.replace("action=view","action=embedview");
url = url.replace("action=interactivepreview","action=embedview");
var session = new OfficeExtension.EmbeddedSession(url, { id: "embed-iframe",container: document.getElementById("iframeHost") });
return session.init().then(function () {
// Initilization is successful
textArea.value = "Initilization is successful";
OfficeExtension.ClientRequestContext._overrideSession = session;
});
}
// Code for getting selected Shape Text using the shapes collection object
function getSelectedShapeText() {
Visio.run(function (ctx) {
var page = ctx.document.getActivePage();
var shapes = page.shapes;
shapes.load();
return ctx.sync().then(function () {
textArea.value = "Please select a Shape in the Diagram";
for(var i=0; i<shapes.items.length;i++)
{
var shape = shapes.items[i];
if ( shape.select == true)
{
textArea.value = shape.text;
return;
}
}
});
}).catch(function(error) {
textArea.value = "Error: ";
if (error instanceof OfficeExtension.Error) {
textArea.value += "Debug info: " + JSON.stringify(error.debugInfo);
}
});
}
</script>
the Issue is Error i coming on click of selected shape Text Button.
Any help would greatly appreciated.Let me know if any query's in case you have not understood my question.
Which URL do you enter? It is supposed to look like this:
..../_layouts/15/WopiFrame.aspx?sourcedoc=%7BXXX-XXX-XX%7D&file=Drawing4.vsdx&action=embedView
Means, you open Visio diagram in SharePoint, copy URL from the address bar and paste it into that field (replace XXXX with your value). If it does not work, replace "default" at the end with "embedView".
I need help populating dropdown list in Alfresco Share. I've created a WebScript API which I read the content of a folder in the repository. As a service in Alfresco (repository) it works. However, I need that DropDown in Share.
Here is what I did in Alfresco:
var folder = roothome.childByNamePath(url.extension);
if (folder == undefined || !folder.isContainer)
{
status.code = 404;
status.message = "Folder " + url.extension + " not found.";
status.redirect = true;
}
model.folder = folder;
<webscript>
<shortname>Folder Listing Sample</shortname>
<description>Sample demonstrating the listing of folder contents</description>
<url>/folder/{path}</url>
<format default="html">argument</format>
<authentication>user</authentication>
<transaction>required</transaction>
</webscript>
<html>
<head>
<title>${folder.displayPath}/${folder.name}</title>
</head>
<body>
Folder: ${folder.displayPath}/${folder.name}
<br>
<select id='selectItems' name='selectItems' onchange='dropdown2()'>
<#list folder.children as child>
<option value='${child.nodeRef}'>${child.properties.name}</option>
</#list>
</select>
</body>
</html>
<#macro encodepath node><#if node.parent?exists><#encodepath node=node.parent/>/${node.name?url}</#if></#macro>
I need this dropdown in Share. Since variables like: userhome, companyhome and such aren't accessible from Share WebScripts, I don't know how to get info from Alfresco and display it in Share. Any help would be appreciated.
From javascript controller of alfresco share, you can call webscript of alfresco and retrieve details from alfresco webscript in json format. Below is one example which is calling alfresco side webscript from share javascript controller.
try
{
var url = "/slingshot/webscript/from/alfresco/url";
logger.log("url: " + url);
// Request the current user's preferences
var result = remote.call(url);
if (result.status == 200 && result != "{}")
{
logger.log(result);
var nodeInfo = eval('(' + result + ')');
nodeRef = nodeInfo.parent.nodeRef;
}
}
catch (e)
{ }
In above url, is of alfresco webscript url which will return data in json format.you can also return data in another format depends on your requirement.
I am using tokbox trial for video chatting on my website. But the problem i am facing is that ::: User 1 can see and hear User 2 clearly. User 2 can see User 1 clearly, but user 2 couldnt here user 1. And code i am using
<html>
<head>
<title>Monkvyasa | Test</title>
<script src='http://static.opentok.com/webrtc/v2.2/js/opentok.min.js'></script>
<script type="text/javascript">
// Initialize API key, session, and token...
// Think of a session as a room, and a token as the key to get in to the room
// Sessions and tokens are generated on your server and passed down to the client
var apiKey = "xxxxxxx";
var API_KEY=apiKey;
var sessionId = "2_MX40NTAyMDgxMn5-xxxxxxxxxxxxxxxxxxxxHBXZEZoWHN-fg";
var token = "T1==cGFydG5lcl9pZD00NTAyMDgxMiZzaWc9ZDNiYjYyZGE2NTBkYmUzMTUyNGNjNDZjYzAzY2NjZWRhZGY3NTEyZjpyb2xlPW1vZGVyYXRvciZzZXNzaW9uX2lkPTJfTVg0xxxxxxxxxxxxxxxxxxxxxxxxBNM1JsYlRCUFdXWkhSSEJYWkVab1dITi1mZyZjcmVhdGVfdGltZT0xNDEzMjAwMjIxJm5vbmNlPTAuMTk1MzEwNTU0MzY1MjEwNSZleHBpcmVfdGltZT0xNDEzMjg0MzY5";
// Initialize session, set up event listeners, and connect
var session;
var connectionCount = 0;
function connect() {
session = TB.initSession(sessionId);
session.addEventListener("sessionConnected", sessionConnectHandler);
session.addEventListener('streamCreated', function(event){
e=event;
console.log(e);
for (var i = 0; i < event.streams.length; i++) {
streams = event.streams;
// Make sure we don't subscribe to ourself
alert("new user connected :)");
if (streams[i].connection.connectionId == session.connection.connectionId) {
return;
}
// Create the div to put the subscriber element in to
var div = document.createElement('div');
div.setAttribute('id', 'stream' + streams[i].streamId);
document.body.appendChild(div);
session.subscribe(streams[i], div.id);
}
});
session.connect(API_KEY, token);
}
function sessionConnectHandler(event) {
var div = document.createElement('div');
div.setAttribute('id', 'publisher');
var publisherContainer = document.getElementById('publisherContainer');
// This example assumes that a publisherContainer div exists
publisherContainer.appendChild(div);
var publisherProperties = {width: 500, height:450};
publisher = TB.initPublisher(API_KEY, 'publisher', publisherProperties);
session.publish(publisher);
}
function disconnect() {
session.disconnect();
}
connect();
</script>
</head>
<body>
<h1>Monkvysa videofeed test!</h1>
<input style="display:block" type="button" id="disconnectBtn" value="Disconnect" onClick="disconnect()">
<table>
<tr>
<td> <div id="publisherContainer"></div></td> <td><div id="myPublisherDiv"></div></td>
</tr>
</table>
</body>
</html>
Thanks in advance
The code looks mostly correct, except you're using an older form of the 'streamCreated' event handler. In the latest version of the API, you no longer need to iterate through the event.streams array, you actually get one invocation of the event handler per stream.
In order to further dig into the problem, would you be able to add a link to a gist containing all the console logs? To make sure the logs are being outputted, you can call OT.setLogLevel(OT.DEBUG); at the beginning of the script.
Lastly, the newer API is greatly simplified and you could save yourself the effort of DOM element creation and iteration. What you have implemented is basically identical to our Hello World sample applications, which you can find in any of our server SDKs, for example here: https://github.com/opentok/opentok-node/blob/61fb4db35334cd30248362e9b10c0bbf5476c802/sample/HelloWorld/public/js/helloworld.js
I have researched and tried everything that I can think of to try and retrieve the actual values for the Iteration, Project, and User columns but I can never get the column data to populate for those like the name of the iteration, name of the project, and name of the submitted by user. I have read that it should be fine to do in the fetch the way I have it and others have said that you have to specify the types with something like this
types : ['defect','user','iteration','project'],
When I do that I dont ever load my grid. I have tried things like this as recommended by some
defect.Iteration.Name
OR
Iteration.Name
I could really use some help here. I also read one article saying the WSAPI no longer supports this kind of request and has to be handled in multiple queries/fetches. Anywho, here is the code that I am using...
function onLoad() {
var rallyDataSource = new rally.sdk.data.RallyDataSource(
'__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
var config = {
type : 'defect',
key : 'defects',
columnKeys : ["FormattedID", "Name", "Priority125", "Iteration", "Project", "SubmittedBy", "CreationDate", "ScheduleState", "State"],
fetch : 'FormattedID,Name,Priority125,Iteration,Project,SubmittedBy,CreationDate,ScheduleState,State',
query : '((State != "Closed") OR (ScheduleState != "Accepted"))',
order : 'Priority125'
};
var table = new rally.sdk.ui.Table(config, rallyDataSource);
table.display("tableDiv");
}
rally.addOnLoad(onLoad);
There are several things needed in order to get this to work as you're wanting:
You can fetch recursively up to a level of one deep. Thus if you want to grab a Defect's Name, Formatted ID, and the Project Name, your fetch would look like:
fetch: "Name,FormattedID,Project,Name"
Grab the data via rallyDataSource.findAll()
Post-process the data so that you feed your table all string data. I.e. clobber Object Reference fields like Project, with the Project Name instead.
Finally, populate and display the table.
Here's working example that illustrates what I think you're wanting to do (minus the "Priority 125" custom field that you have defined).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- Copyright (c) 2011 Rally Software Development Corp. All rights reserved -->
<html>
<head>
<title>Defect Information</title>
<meta name="Name" content="Defect Information" />
<meta name="Version" content="1.32" />
<meta name="Vendor" content="Rally Software" />
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.32/sdk.js?debug=True"></script>
<script type="text/javascript">
var rallyDataSource = null;
var table = null;
function showTable(results) {
if (table) {
table.destroy();
}
var tableConfig = {
columnKeys : ["FormattedID", "Name", "Iteration", "Project", "SubmittedBy", "CreationDate", "ScheduleState", "State"],
columnWidths : ["85px", "350px", "90px", "100px", "100px", "120px", "100px", "100px" ]
};
table = new rally.sdk.ui.Table(tableConfig);
// Loop through the rows and clobber object attributes of the results collection with
// string values
for(var i = 0; i < results.defects.length; i++){
thisDefect = results.defects[i];
var iterationName = "";
// Grab value fields
if (thisDefect.Iteration != null) {
iterationName = results.defects[i].Iteration.Name;
} else {
iterationName = "Un-scheduled";
}
var projectName = thisDefect.Project.Name;
// Re-map SubmittedBy object to SubmittedBy string
submittedByDisplayName = thisDefect.SubmittedBy === null ? "": thisDefect.SubmittedBy._refObjectName;
// Clober objects with values
results.defects[i].Iteration = iterationName;
results.defects[i].Project = projectName;
results.defects[i].SubmittedBy = submittedByDisplayName;
}
table.addRows(results.defects);
table.display(document.getElementById('defectsDiv'));
}
function onLoad() {
rallyDataSource = new rally.sdk.data.RallyDataSource(
'__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
var config = {
type : 'defect',
key : 'defects',
fetch: 'FormattedID,Name,SubmittedBy,Iteration,Name,Project,Name,CreationDate,ScheduleState,State',
query : '((State != "Closed") OR (ScheduleState != "Accepted"))',
};
rallyDataSource.findAll(config, showTable);
rallyDataSource.setApiVersion("1.38");
}
rally.addOnLoad(onLoad);
</script>
</head>
<body>
<div id="aDiv"></div>
<div style="font-weight: bold;"><p>Defects</p></div>
<div id="defectsDiv"></div>
</body>
</html>