Why are my promoted variables are not shared between Workshop modules in Carbon? - palantir-foundry

I have a carbon workspace with two workshop modules. One of them includes a button that opens another workshop module and should pass a promoted variable (an array) to the new module.
But when the second module is opened via the button it looks like the variable was never passed along.

In the network tab it should show an error like the below:
foundry.objects.workshop.app.workshopModuleParameters: Tried passing a list parameter when opening another Workshop module in Carbon, but list parameters are not currently supported by Carbon, so ignoring the parameter value
In that case there are two options, one is to move to non-array variables if possible:
The other one is to use a function that would take the array, convert it into a string with a specific delimiter and pass this string variable to the new module:
#Function()
public makeString(arrayToConvert: string[]): string{
var convertedString = arrayToConvert[0];
if(arrayToConvert.length===1){
return convertedString
}
for (let i =1; i<arrayToConvert.length; i++){
convertedString = convertedString.concat(",", arrayToConvert[i])
}
return convertedString;
}
Convert the array to a string with a variable:
And pass the string variable to the new module:
In the second module the string would be converted back into an array.
#Function()
public makeArray(stringToConvert: string): string[]{
var convertedArray = stringToConvert.split(",");
return convertedArray;
}

Related

Casting JSON to complex types

I am trying to cast my http.get response to actual object -> in my specific case array of complex objects.
In a normal scenario, where you don't need any specific casting, you could do the following (simplified):
return this.httpClient.get(api, this._options_get)
.pipe(
map((response: any) => {
return response.value as NewProduct[];
})
);
As my need is to actually cast this to an object, I have created this static method which does that:
static toProduct(otherProduct: any): NewProduct {
let item = new NewProduct();
Object.keys(otherProduct).forEach(prop => {
if (typeof otherProduct[prop] === "object" && otherProduct[prop]) {
if (!item.hasOwnProperty(prop))
item[prop] = otherProduct[prop];
Object.assign(item[prop], otherProduct[prop]);
}
else
item[prop] = otherProduct[prop];
})
return item;
}
Under Object.assign I am taking already existing object which was initialized under first line and I am simply copying all the properties from the otherProduct to it. However I start to face problem when it comes to array of objects. Example (with simplified class):
export class Person {
name:string;
age:number;
addresses:Address[] = [];
}
export class Address {
street:string;
city:string;
fullAddress() : string { return this.street + this.city; }
}
As soon as I have this sort of array, I don't have any initial object in item. This means that there is no initial constructor of a class which results in simple Object. This is no error for JavaScript or TypeScript; however when I am trying to access internal method of a class (in our simplified case fullAddress(), I won't be able to.
The reason why I need that is that I am overriding toString() method on my sub-classes, which is necessary for MatTableDataSource when you use the filter method (which works with strings).
Is there a way how to retrieve elements from http.get() and properly map results to typed objects?
You're being too generic. You're creating objects of objects, not objects of Product with children of Addresses.
If you want to create a new product you're going to have to understand the relationship between the api's results and the data you want in the UI.
Because you're using classes and not interfaces and want to inherit the functions, the only way to get new Addresses into the new object is with the new keyword.
And you'll have to loop through. You're not going to find a shortcut for this. You're going to need to loop through the data and transform it. If your api is giving you an ApiPerson then you'll want to do something like this:
const addresses = apiPerson.addresses.map((apiAddress) => {
const address = new Address();
// map properties of apiAddress to address...
return address;
});
Now that you have the addresses, you can map the apiPerson to a new Person()'s properties and then set the newPerson.addresses = address.

SSIS script task can't read project variable

In my project.params I have variables such as LampUserName of type string. In my
script task I'm then trying to read them like so:
foreach (var name in new string[] { "ServerName", "InitialCatalog", "UserName", "Password" }) {
if (!Dts.Variables.Contains(string.Format("$Project::Lamp{0}", name))) {
writer.WriteLine(name);
}
}
string server_name = (string)Dts.Variables["$Project::LampServerName"].Value;
string database = (string)Dts.Variables["$Project::LampInitialCatalog"].Value;
string username = (string)Dts.Variables["$Project::LampUserName"].Value;
string password = (string)Dts.Variables["$Project::LampPassword"].Value;
Every one of those prints out that it doesn't exist and then an exception is thrown. What am I doing wrong?
Are you referencing your project parameters from a Script Component within a Data Flow Task? If so, this differs from using a Script Task within the Control Flow. After adding the project parameter in the ReadOnlyVaraiables field, it is accessible as a property of the Variable object.
string database = Variables.DatabaseParameter.ToString();

Can a second parameter be passed to Controller constructors?

Castle Windsor passes the registered concrete type to Controller's constructors. A typical implementation (no pun intended) is:
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository");
}
_deptsRepository = deptsRepository;
}
I need to pass the ctor a second parameter, if possible, so that I can pass that val on to the Repository constructor (I know: tramp data alert, but I don't know if there's a straightforward way around it:
public DepartmentsController(IDepartmentRepository deptsRepository, int DBInstance)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository");
}
_deptsRepository = deptsRepository(DBInstance);
}
REPOSITORY
public DepartmentRepository(int dbInst)
{
string connStr = string.Format("Phoo{0}Bar", dbInst);
using (var conn = new OleDbConnection(connStr))
{
using (var cmd = conn.CreateCommand())
{
. . .
Is it possible to tweak what Castle Windsor sends to the Controller constructor this way? If so, how?
AND/BUT: For this to be of any value (to me, anyway), I need to be able to get the int val (that will be passed to the Controller) from the URL the client sends. IOW, if the client asks the server for data via:
http://locohost:4242/Platypus/GetAll/1
I need to pass a "1" as the second argument to PlatypusController.
If the user asks the server for data via:
http://locohost:4242/Platypus/GetAll/42
I need to pass a "42" as the second argument to PlatypusController.
etc.
This is what I did to solve my Controller/Repository data context Dilemma:
0) Added a database context argument to the Controller's routing attribute. IOW, this:
[Route("api/HHSUsers/GetAll")]
...got changed to this:
[Route("api/HHSUsers/GetAll/{dbContext=03}")]
1) Passed that database context arg to the Repository. To wit, this:
return _hhsusersrepository.GetAll();
...got changed to this:
return _hhsusersrepository.GetAll(dbContext);
...so that the Controller method is now:
[Route("api/HHSUsers/GetAll/{dbContext=03}")]
public IEnumerable<HHSUsers> GetAllHHSUsersRecords(int dbContext)
{
return _hhsusersrepository.GetAll(dbContext);
}
2) Changed the corresponding method in the Repository interface from:
IEnumerable<HHSUsers> GetAll();
...to this:
IEnumerable<HHSUsers> GetAll(string dbContext);
3) Changed the Repository method from this:
public HHSUsersRepository()
{
// All the data is loaded here in the ctor
}
public IEnumerable<HHSUsers> GetAll()
{
return hhsusers;
}
....to this:
public IEnumerable<HHSUsers> GetAll(string dbContext)
{
LoadHHSUsers(dbContext);
return hhsusers;
}
private void LoadHHSUsers(int dbContext)
{
string connStr = string.Format("Foo{0}Bar", dbContext);
// The same as previously from this point on, except that this:
// using (var conn = new OleDbConnection(#"Foo Bar Phoo Bar etc"...
// becomes:
// using (var conn = new OleDbConnection(connStr))
4) Tack the dbcontext val to the end of the URL when calling the method, so that it is this:
http://localhost:28642/api/HHSUsers/GetAll/42
...instead of this:
http://localhost:28642/api/HHSUsers/GetAll
If the data context to use is "03" I can omit the dbcontext arg from the URL, as 03 is the default value I set when I appended "=03" to the Controller's "dbContext" routing attribute arg.
I know some fancy-pants propeller-heads will find fault with this for some reason (for one reason because of the tramp data going here and there and everywhere like a hobo on steroids), but my response is the same as that of an athlete who is getting trash-talked by an opposing player and yet whose team is winning: just point at the scoreboard. IOW, this works for me, so that's pretty much all I care about. Style points are for runway models and, again, fancy-pants propeller-heads (AKA Star-Bellied Sneeches (as opposed to us plain
cats with the unstarred bellies)); see "The perfect is the enemy of the good."
This simple way has that self-same benefit -- of being (relatively) simple to grok and, thus, modify/refactor as necessary. Inelegant? Sure, but so was Joe Kapp.

SSIS package : Store value of for loop variable in an array

I am creating an SSIS package where I have to iterate through some of the selected folder and I want to store the folder names in an array to keep track of folders that I have processed. Can I keep an array in SSIS package and keep appending the value in that array?
You can store the value of a for loop variable in an array. Doing this is a little messy IMO. There's likely a cleaner approach using "out of the box" SSIS functionality as #billinkc suggested. However, here are some pointers ...
Let's go with your scenario where you have a for each loop that iterates over some files (using a Foreach File Enumerator) and you want to store the folder names in an array.
Here are some variables we'll use:
FolderList will be the array and CurrentFile will be the for loop variable. The package in its simplest form might look like this:
In the script task, the code might look like this. I've chosen to use a List<string> as my array type, but you could use something else, such as ArrayList. (Note: you'll need to add using statements for System.Collections.Generic and System.IO for the code below):
public void Main()
{
//get current directory
string directory = Path.GetDirectoryName(Dts.Variables["User::CurrentFile"].Value.ToString());
List<string> lst = new List<string>();
// if the FolderList is already a List<string> then set set it to lst
if ((Dts.Variables["User::FolderList"].Value is List<string>))
{
lst = (List<string>)Dts.Variables["User::FolderList"].Value;
}
// if the directory isn't in the list yet, then add it to the list
if(!lst.Contains(directory))
{
lst.Add(directory);
}
// update our variable with the List<string>
Dts.Variables["User::FolderList"].Value = lst;
Dts.TaskResult = (int)ScriptResults.Success;
}
Each time the Script Task is executed, you'll get a new folder added to the array. Once the for each loop is done, you may want to examine the values of the array. You can do this using a Script Task (similar to what we did above):
List<string> lst = (List<string>)Dts.Variables["User::FolderList"].Value;
// do stuff with lst
You can also iterate over the values in the array using a for each loop (use the Foreach From Variable Enumerator), which I just learned as I was walking through this (thanks!). Just set the variable to enumerate over to your array variable (here FolderList) and specify another variable (e.g. CurrentFolder) as index 0 in Variable Mappings. This worked for a List<string>, but I'm not sure what other collection types it would work with.

jqGrid Add Row Data Nested Object

I have a column model like that:
...
{name:'password',index:'password', width:100},
{name:'type.name',index:'type.name', width:100},
...
My class like definitons:
var MyObject = function (password, type) {
this.password = password;
this.type = type;
};
var MyType = function (tname) {
this.tname = tname;
};
I populate my variables: like that:
var type = new MyType($('#typeList').val());
var myObject = new MyObject($('#password').val(), type);
I have a JSON data response from my server and some of it's elements are object as like type. When I want to show them at my grid its OK. However when I want to use addrowdata function I can not see anything at type column. I am doing like that:
$("#gridId").jqGrid('addRowData', myObject.password, myObject, "first");
class is the function that hold name, password etc. inside it. The problem is only with nested elements(I can see password etc. at my grid). addrowData fonction accepts an array but I send a abject that holds object. How can I convert my object of objects into a plaint object array?
Any ideas?
You should not use points in the name property! If needed you can use if in index or in jsonmap.
The usage of addRowData in your example seems me wrong. You should reread the documentation of addRowData method.