Wsapi data store query - rally

I am looking to get all projects under a selected project (i.e the entire child project branch ) using Wsapi data store query in Rally SDK 2.0rc1. Is it possible using a query to recursively get all child project names? or will I have to write a separate recursive function to get that information? If a separate recursive function is required, how should I populate that data into for example, a combo box? Do I need to create a separate data store and push the data from my recursive function in it and then link the Combobox's store to it?
Also, how to get the "current workspace name" (workspace that I am working in, inside Rally), in Rally SDK 2.0rc1 ?

Use the 'context' config option to specify which project level to start at and add 'projectScopeDown' to make sure child projects are returned. That would look something like this:
Ext.create('Rally.data.WsapiDataStore', {
limit : Infinity,
model : 'Project',
fetch : ['Name','ObjectID'],
context : {
project : '/project/' + PROJECT_OID,
projectScopeDown : true
}
}).load({
callback: function(store) {
//Use project store data here
}
});
To get your current context data, use: this.getContext().
var workspace = this.getContext().getWorkspace();
var project = this.getContext().getProject();

If you try exposing with console.log the this.getContext().getWorkspace() and this.getContext().getProject() you may understand better what is returned and what is required. In one of my cases I had to use this.getContext().getProject().project.
Using console debug statement is best way to figure what you need based on its usage.

Related

KeystoneJS `filter` vs `Item` list access control

I am trying to understand more in depth the difference between filter and item access control.
Basically I understand that Item access control is, sort of, higher order check and will run before the GraphQL filter.
My question is, if I am doing a filter on a specific field while updating, for instance a groupID or something like this, do I need to do the same check in Item Access Control?
This will cause an extra database query that will be part of the filter.
Any thoughts on that?
The TL;DR answer...
if I am doing a filter on a specific field [..] do I need to do the same check in Item Access Control?
No, you only need to apply the restriction in one place or the other.
Generally speaking, if you can describe the restriction using filter access control (ie. as a graphQL-style filter, with the args provided) then that's the best place to do it. But, if your access control needs to behave differently based on values in the current item or the specific changes being made, item access control may be required.
Background
Access control in Keystone can be a little hard to get your head around but it's actually very powerful and the design has good reasons behind it. Let me attempt to clarify:
Filter access control is applied by adding conditions to the queries run against the database.
Imagine a content system with lists for users and posts. Users can author a post but some posts are also editable by everyone. The Post list config might have something like this:
// ..
access: {
filter: {
update: () => ({ isEditable: { equals: true } }),
}
},
// ..
What that's effectively doing is adding a condition to all update queries run for this list. So if you update a post like this:
mutation {
updatePost(where: { id: "123"}, data: { title: "Best Pizza" }) {
id name
}
}
The SQL that runs might look like this:
update "Post"
set title = 'Best Pizza'
where id = 234 and "isEditable" = true;
Note the isEditable condition that's automatically added by the update filter. This is pretty powerful in some ways but also has its limits – filter access control functions can only return GraphQL-style filters which prevents them from operating on things like virtual fields, which can't be filtered on (as they don't exist in the database). They also can't apply different filters depending on the item's current values or the specific updates being performed.
Filter access control functions can access the current session, so can do things like this:
filter: {
// If the current user is an admin don't apply the usual filter for editability
update: (session) => {
return session.isAdmin ? {} : { isEditable: { equals: true } };
},
}
But you couldn't do something like this, referencing the current item data:
filter: {
// ⚠️ this is broken; filter access control functions don't receive the current item ⚠️
// The current user can update any post they authored, regardless of the isEditable flag
update: (session, item) => {
return item.author === session.itemId ? {} : { isEditable: { equals: true } };
},
}
The benefit of filter access control is it doesn't force Keystone to read an item before an operation occurs; the filter is effectively added to the operation itself. This can makes them more efficient for the DB but does limit them somewhat. Note that things like hooks may also cause an item to be read before an operation is performed so this performance difference isn't always evident.
Item access control is applied in the application layer, by evaluating the JS function supplied against the existing item and/or the new data supplied.
This makes them a lot more powerful in some respects. You can, for example, implement the previous use case, where authors are allowed to update their own posts, like this:
item: {
// The current user can update any post they authored, regardless of the isEditable flag
update: (session, item) => {
return item.author === session.itemId || item.isEditable;
},
}
Or add further restrictions based on the specific updates being made, by referencing the inputData argument.
So item access control is arguably more powerful but they can have significant performance implications – not so much for mutations which are likely to be performed in small quantities, but definitely for read operations. In fact, Keystone won't let you define item access control for read operations. If you stop and think about this, you might see why – doing so would require reading all items in the list out of the DB and running the access control function against each one, every time a list was read. As such, the items accessible can only be restricted using filter access control.
Tip: If you think you need item access control for reads, consider putting the relevant business logic in a resolveInput hook that flattens stores the relevant values as fields, then referencing those fields using filter access control.
Hope that helps

Storing custom application configurations on cumulocity

Is there a way to store custom application configurations on the Cumulocity backend through the c8y.sdk? I would like to store a JSON with configuration information specific to an application created using the the smart app toolkit.
You can save settings at the tenant by using c8ySettings,
BUT you have a limitation of 256 characters per value.
I'm struggling with the same problem of storing larger plugin configurations without any success.
I asked about this from cumulocity support and they said it is possible to store custom JSON under managedobjects because at the moment they dont support storing JSON to database otherwise.
So you will need "create" or "admin" rights to inventory to be able to create new managedobject. You can store values like this:
var userSettings = {
type: 'userDashboardSettings',
yourSetting: somesetting,
id: settingsId
};
c8yInventory.save(userSettings).then(function(){
//do something
});
then you can search this newly created managedobject like this:
c8yInventory.list({
type: 'userDashboardSettings',
owner: id,
pageSize: 2
}).then(function (settings) { //do something }
So this way I was for example able to save user specific settings.
To find user dashboard settings do GET to: https://yourdomain.com/inventory/managedObjects/?type=userDashboardSettings&owner=IDHERE
To Delete managedObject do DELETE to: https://yourdomain.com/inventory/managedObjects/IDHERE
To see all managedObjects do GET: https://yourdomain.com/inventory/managedObjects
Type and user are important, this is how you find the managedobject.

Query to get all projects in a workspace using lookback api

Is Project a valid _Type to use in a lookback lquery?
I tried "_Type":"Project"
https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/1234/artifact/snapshot/query.js?find={"_Type":"Project","State":"Open"}&fields=["Name"]
and also "_TypeHierarchy":"Project"
https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/1234/artifact/snapshot/query.js?find={"_TypeHierarchy":"Project","State":"Open"}&fields=["Name"]
and both returned 0 results. The same syntax works if "_TypeHierarchy":"Defect" but not with Project, but there are no errors. Thanks.
The Lookback API supports querying snapshots for a given Project or ProjectHierarchy. For example:
{
[...]
"Project": 12345
}
or
{
[...]
"_ProjectHierarchy": 12345
}
However, it's not possible get a list of projects from the Lookback API outside the context of artifact snapshots. Getting projects would be a manual process. If you get a list of snapshots, you could iterate the result set and extract the Project OIDs, then generate a list. You could even parse the _ProjectHierarchy values and construct the project tree. Another caveat is hydrating the Project OIDs will require WSAPI calls.
Querying projects from the Lookback API may be expensive. You can specify fields to reduce the amount of data in the response. e.g.
fields: ["Project", "_ProjectHierarchy"]

Query allowed values of an attribute in Rally using javascript

Could someone tell me how to query allowed values of an attribute in Rally using javascript?
Particularly, I want to query all possible states of a Defect
I know that it can be done with REST api
DynamicJsonObject allowedValues = restApi.GetAllowedAttributeValues("defect", "state");
Is there a javascript equivalence?
You can use RallyDataSource from the App SDK (note, this is the original one, not the new ExtJS-based SDK currently in preview). See the Attribute Values example on this page:
http://developer.rallydev.com/help/data-examples
You may wish to try something along the lines of:
queryConfig = {
type: 'Defect',
key : 'defectStates',
attribute: 'State'
};

Data structure to use in Sencha Touch similar to Vector in Blackberry

I am a beginner to sencha Touch, basically i am a blackberry developer. Currently we are migrating our application to support Sencha Touch 1.1. Now i have some business solutions like i want to store the selected values in the local database. I mean i have multiple screens where, Once the user selects a value in each of the screen the data should save in the below following format.
[{'key1': "value1", 'key2': "value2", 'key3': "value3" ,'key4': "value4", 'key5': "value5"}]
1. First, the values need to be saved in key value pairs
2. The keys should play the role of primary key, key shouldn't be duplicated.
3. Should be available till the application life cycle or application session, don't need to save the data permanently.
I have come across the concepts like LocalStorageProxy, JsonStore and some others. I don't understand which one i can use for my specific requirements.
May be my question is bit more confusing. I have achieved the same using vector, in Blackberry Java so any data structure similar to this could help me. Need the basic operations like
Create
Add
Remove
Remove all
Fetch elements based on key
Please suggest me some samples or some code snapshots, which may help me to achieve this.
Edit: 1
I have done the changes as per #Ilya139 's answer. Now I am able to add the data with key,
// this is my Object declared in App.js
NSDictionary: {},
// adding the data to object with key
MyApp.NSDictionary['PROD'] = 'SONY JUKE BOX';
//trying to retrieve the elements from vector
var prod = MyApp.NSDictionary['PROD'];
Nut not able to retrieve the elements using the above syntax.
If you don't need to save the data permanently then you can just have a global object with the properties you need. First define the object like this:
new Ext.Application({
name: 'MyApp',
vectorYouNeed: {},
launch: function () { ...
Then add the key-value pairs to the object like this
MyApp.vectorYouNeed[key] = value;
And fetch them like this
value = MyApp.vectorYouNeed[key];
Note that key is a string object i.e. var key='key1'; and value can be any type of object.
To remove one value MyApp.vectorYouNeed[key] = null; And to remove all of them MyApp.vectorYouNeed = {};