Creating multi drop down columns using the smartsheet api - smartsheet-api

Very recently a new type of column was add to smartsheet : multi drop down :
Is there any solution to create such column using the api ?
Is a new version of the api planned ?

As of Oct 1, you can actually create a column that supports the new multi-dropdown feature. The documentation is a little behind.
If you don't yet have a column, you'll have to Add a column first.
Once you have a columnId, you can send an Update Column request and specify "type" as "MULTI_PICKLIST".
To retrieve the correct type when you do a GET /sheets/{sheetId} or GET /{columnId}, you have to use a query parameter of ?level=3&include=objectValue.

It is possible to create a Dropdown (multi select) column via the API!
To briefly address the TEXT_NUMBER issue, this type is used for backwards-compatibility. If you are unaware of the ?level=2&include=objectValue suffix, the response will return a TEXT_NUMBER column type to avoid breaking any existing clients that aren't set up to handle the new column type.
In the following examples the double brace variables represent your targets:
{{environment}} is something like https://api.smartsheet.com/2.0/
{{sheetId}} is a sheet Id in the form 6264126827992742
{{columnId}} is the Id of your primary column in the form 2641268279927426
{{columnId2}} is the Id of your multi picklist column in the form 6412682799274262
To add a column with a MULTI_PICKLIST type to an existing sheet:
POST: {{environment}}/sheets/{{sheetId}}/columns/
{
"title": "I'm a new multi picklist column",
"type":"MULTI_PICKLIST",
"index": 1,
"options": ["opt1","opt2","opt3"]
}
To create a column on a brand new sheet, this example will create a sheet with a primary column, a MULTI_PICKLIST column, and then add a row with some data.
Then it will get the sheet using level 2 to avoid the backwards compatibility TEXT_NUMBER type.
To create a sheet with a MULTI_PICKLIST column:
POST: {{environment}}/sheets
{
"name":"API PL Sheet",
"columns":
[
{
"title":"My primary Column",
"primary":true,
"type":"TEXT_NUMBER"
},
{
"title":"My multi select column",
"type":"MULTI_PICKLIST",
"options":["options","in","this","form"]
}
]
}
To add a row on this sheet:
POST: {{environment}}/sheets/{{sheetId}}/rows?include=objectValue
[
{
"toTop": true,
"cells":
[
{
"columnId":{{columnId}},
"value": "1"
},
{
"columnId":{{columnId2}},
"objectValue":
{
"objectType":"MULTI_PICKLIST",
"values":["in", "form"]
}
}
]
}
]
To view the sheet with the MULTI_PICKLIST objectValue:
GET: {{environment}}/sheets/{{sheetId}}?level=2&include=objectValue
If you do not include the ?level=2&include=objectValue suffix then the JSON response will have columns that appear as though they are TEXT_NUMBER types.
For one final note, different endpoint groups require different levels. They are as follows:
GET Cell History is level 2
GET Sheets is level 2
GET Row is level 2
GET Column is level 2
POST Sort is level 2
GET Sights (dashboards) is level 3
GET reports is level 3

Related

ServiceNow REST API: Get list of column names

From the admin UI, there is a Tables and Columns explorer that dutifully shows all available columns for a table, such as the incident table:
My ultimate goal is to be able to query all fields for a given table that I can insert data to (mostly centered around incident and problem tables), match that against what data I have, and then insert the record with a PUT to the table. The immediate problem I am having is that when I query sys_dictionary as various forums suggest, I only get returned a subset of the columns the UI displays.
Postman query:
https://{{SNOW_INSTANCE}}.service-now.com/api/now/table/sys_dictionary?sysparm_fields=internal_type,sys_name,name,read_only,max_length,active,mandatory,comments,sys_created_by,element&name={{TableName}}&sysparm_display_value=all
I understand the reduced result set has something to do with them being real columns in the table vs. links to other tables but I can't find any documentation describing how to get the result set that the UI has using the REST api.
The follow on problem is that I can't find an example with an example payload where all standard fields have been filled out for the incident table so that I can populate as many fields as I have data for.
The reason you don't get all the columns back is because the table you are querying inherits from another table. You need to go through all the inheritance relationships first, finding all parent tables, then query the sys_dictionary for all of those tables.
In the case of the incident table, you need to query the sys_db_object table (table of all tables) to find the parent, which is the task table. Then query the sys_db_object table again to find its parent, which is empty, so we have all the relevant tables: incident and task. Obviously, you would want to write this code as a loop, building up a list of tables by querying the table at the end of the list.
Once you have this list, you can query sys_dictionary with the query: sysparm_query=name=incident^ORname=task, which should return your full list of columns.
I think you could do this by creating your own scripted rest api and iterating/inspecting the fields:
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var queryParams = request.queryParams;
var table = queryParams.table;
var t = new GlideRecord(table);
t.initialize();
var fields = t.getElements(); //or getFields if global scope
var fieldList = [];
for (var i = 0; i < fields.length; i++) {
var glideElement = fields[i]; //or field.get(i) if global scope
var descriptor = glideElement.getED();
var fldName = glideElement.getName().toString();
var fldLabel = descriptor.getLabel().toString();
var fldType = descriptor.getInternalType().toString();
var canWrite = glideElement.canWrite();
if (canWrite){
fieldList.push({
name: fldName,
type: fldType,
label: fldLabel,
writable: canWrite
});
}
}
return fieldList;
})(request, response);
This should save you the hassle of determining the inheritance of fields. Here's the sample output:
{
"result": [
{
"name": "parent",
"type": "reference",
"label": "Parent",
"writable": true
},
{
"name": "made_sla",
"type": "boolean",
"label": "Made SLA",
"writable": true
},
...

UI5 - how to dynamically bind data to a Select in Table, depending on another combobox?

I have a classic situation - a table with two comboboxes (or, to be exact, sap.m.Select controls) and after select in the first one, I would like to have the values in the second one updated. This is my model, basically, the first combobox should contain the list of available states and once some is selected, the second sap.m.Select control should be populated by relevant cities
{
countries: [
{ country: 'France', cities: ['Paris', 'Marseille', 'Lyon']},
{ country: 'Germany', cities: ['Berlin', 'Bonn']}
]
}
The problem is that I dont know how to do it. I am able to get the id of the updated row using something like this.
onCountryChange: function (oEvent) {
const selectedItem = oEvent.getParameter("selectedItem");
var path = selectedItem.getBindingContext().getPath();
bindComboBox(path); // this should rebind the data, but not written yet
}
I know now I should rebind the data in the correct combobox, however, I don't know how to affect only that single combobox on the correct row and how to update it. Could someone advise me how to do it? The whole table is defined in the .xml view, can I do it also with a formatter or inline expression or is this scenario too difficult for that?
Thank you
You can use the bindAggregation method (from the ManagedObject) class to rebind the combo boxes' items.
onCountryChange: function (oEvent) {
const selectedItem = oEvent.getParameter("selectedItem");
var path = selectedItem.getBindingContext().getPath();
this.byId("combo2").bindAggregation("items", {
path: path + "/cities",
template: new sap.ui.core.Item({
key: "{}",
text: "{}"
})
});
}
Note: Replacing "combo2" with the id of your 2nd combo box/select control.
Edit: To get the correct combo box (assuming you have multiple created on a table, use the ID of the first combo box (oEvent.getSource().getId()) to generate the ID of the 2nd combo box. Without knowing more of the structure of the table (and how it's created) I can't offer more.

Google Sheets REST API 4 get row with specific column

I want to get only one row that contain specific value in one column.
How to make query and set something like: IF "column1" = '3' return that row?
If i use sheets.spreadsheets.values.batchGetByDataFilter
i don't know what to write in DataFilter (now i write only "A:D" to return all rows and columns)
POST https://sheets.googleapis.com/v4/spreadsheets/<Sheet_ID>/values:batchGetByDataFilter?key={YOUR_API_KEY}
{
"dataFilters": [
{
"a1Range": "A:D"
}
]
}

Update work item relations/links in VS Team Services

I am trying to use the VSTS API to remove all parent links on items, and set those parents as related items.
https://www.visualstudio.com/en-us/docs/integrate/api/wit/work-items#update-work-items
I do not fully understand how the "Path" needed to remove relations work – I am getting inconsistent results where sometimes it works, sometimes not (so, im clearly doing it wrong)
I am making an assumption that its simply the order returned by the API. So, for example:
Index[0] item
Index[1] item
Index[2] item <- this is the one I want to remove, so I use index 2
public void RemoveParentLink(int pathIndex, int itemToUpdate, string link)
{
JsonPatchDocument patchDocument = new JsonPatchDocument();
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Remove,
Path = $"/relations/{pathIndex}"
}
);
WorkItem result = witClient.UpdateWorkItemAsync(patchDocument, itemToUpdate).Result;
}
The documentation states that Path is:
Path to the value you want to add, replace, remove, or test.
For a specific relation, use "relations/Id".
For all relations, use "/relations/-".
Index is NOT the Id of course, but how do I get the relation/Id exactly?
Using GetWorkItemAsync or GetWorkItemsAsync with WorkItemExpand.Relations parameter to get linked work items.
Var workItem=witClient.GetWorkItemAsync(id: [work item id], expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.Relations).Result.
Then the index is the index of relations.
The 'id' in the '/relation/id' path is a index in fact. You retrieve the work item definition, then the 'id' is the index of the link in the 'relations' array. Hence your assumption is right.
Evidence: given a work item with 2 links, if you try to delete/modify id >= 2 it will answer with:
{ "$id": "1", "innerException": null, "message": "Index out of range
for path /relations/2.", "typeName":
"Microsoft.VisualStudio.Services.WebApi.Patch.PatchOperationFailedException,
Microsoft.VisualStudio.Services.WebApi, Version=14.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "typeKey":
"PatchOperationFailedException", "errorCode": 0, "eventId": 3000 }
0 and 1 as id work just fine instead.
I may be wrong, but I could guess that you could get an error when using the 'replace' operation before the 'add' operation. For example you need to add a 'comment' inside the 'attributes' of a link before modifying (i.e. 'replace' operation) its value.

Using MapReduce/Aggregation to create search facets

I have the documents of the following prototype:
{
title: "HD8200 DLP Projector",
normal_price: 4999.99,
specifications: [
{
ov: "HD (1920 x 1080)",
fn: "Resolution (Native / Max)",
o: 7,
f: 211
},
{
ov: "20000",
fn: "Contrast Ratio",
o: 15,
f: 225
}
]
}
I'm looking to create a list of filters for this product database, based on the specifications.
How can I get a list of option IDs (o) mapped to their product counter, for each field (f)?
Let's assume I need to achieve this for a specific list of field IDs (say, 211 and 225).
Write a mapper to take one document per map() call and write out a record for each option. The record key would be the field ID and the value would be a concatenation of a flag "1", the product title and option ID.
Write another mapper to read the list of id's and to write out a record with the same format: the key is the field ID and the value is a concatenation of a flag "0" and two empty strings.
Write a Reducer to read in the records written by the two mappers. Each call to reducer() will pass in all records written for a given field. If one of those records has a "0" flag then that field was one of the fields you're interested in. Only then would you write out a record for each record with a "1" flag. The key is the product title and the value is the option id.
Define your first job driver class to use the two mappers and the one reducer. This step will come up with pairs of product-options for the field id's you specify. You'll need a second job to gather the options by product, or vide versa.