User Specific App Settings - rally

I have started working with server side app settings and it would appear the default mechanics for a shared app is to save the app settings across the entire project scope; so if an individual makes changes to the app settings, those changes are reflected for all future users. This is not the ideal use in my specific case. I would like it if I could have different settings for each user, without them each adding separate instances of my custom HTML. Is this possible using server side settings, or will I need to look into using cookies to save the settings on each user?
Note: I've read the documentation on app setting scope (https://help.rallydev.com/apps/2.0rc1/doc/#!/guide/settings-section-define-scope) but it doesn't appear as though "user" is an option.
Thanks!

Conner, you're making a good argument for User-level settings for an app.
Unfortunately, we don't support that currently. The settingsScope option in AppSettings only supports the values app, project, or workspace.
Creating an instance of the app for each user (such as on their individual dashboard) is the best alternative I can think of. But as you mentioned, this is not ideal for you.

I have solved this issue by prepending the user ObjectID to each setting value before I save or load it from the Rally servers. Here is the code for my user settings set/get functions:
setUserSetting : function(settingName, settingValue, callback) {
var settings = {};
settings[App.getContext().getUser().ObjectID + settingName] = settingValue;
App.updateSettingsValues({
settings : settings,
success : function() {
App.setSettings(Ext.Object.merge(App.getSettings(), settings));
callback();
}
});
},
getUserSetting : function(settingName) {
return App.getSetting(App.getContext().getUser().ObjectID + settingName);
}
BTW, it seems kind of strange that I have to save the settings in the way I have. The "updateSettingsValues" function sets the settings on the next load of the app and the "setSettings" function sets it for the current runtime of the app. It's a strange way to have to do it, but it works.

Related

Store an array on the app group for WidgetKit

I'm trying to store an struct array into the app group container to use it later on the widget.
let's assume, I have an array of string
let = array = ["object1", "object2", "object3"]
and I saw here I can access to the app group container url
let applicationGroupId = "group.com.development.widget"
guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: applicationGroupId) else {
fatalError("could not get shared app group directory.")
}
Now, I need to know how I can store this array on app group and how I can read from it on the Widgetkit SwiftUI class
Your help will be appreciated.
Signing, Capabilities, Entitlements
Right now it should be possible to do all of this from within Xcode (12+). In the app's project settings go to the Signing & Capabilities tab and make sure Automatically manage signing is enabled and the Team has a valid development team (either company or personal account).
Tap on the + Capability button on the top left to enter the App Group Capability (this will also add an entitlements file). Now you will find an App Group section. Hit the + button for App Groups and enter a globally unique identifier (something like group.<appid>). This will create the app group on the developer platform and add it to your app's provisioning profile and entitlements.
You must repeat the same steps and use the same app group for all targets (app target, widget extension target and (optionally) intent targets). If you hit the reload button for the other targets' app group it should automatically show the app group you previously registered and you can check the checkbox. If not, hitting + and using the same id should work as well.
Finally, check all entitlements files and ensure that they have the same String in App Groups (copy and paste just to make sure).
Code
In code you now just have to access the user defaults using the chosen app group as suitName. To test whether everything is set up correctly, I would put the following line in application(_:didFinishLaunchingWithOptions):
UserDefaults(suiteName: "group.id.test")!.setValue(["object1", "object2", "object3"], forKey: "test")
In the Widget just try to put it in a Text view:
struct WidgetTestEntryView : View {
var entry: Provider.Entry
var text: String {
(UserDefaults(suiteName: "group.id.test")!.value(forKey: "test") as? [String])?.joined(separator: " ") ?? "Nothing stored yet"
}
var body: some View {
Text(text)
}
}
Note: I force unwrap the user defaults on purpose to fail early and check whether the setup of capabilities/signing worked. In production you should guard against a failure.
Alternative Storage
As you pointed out it's also possible to persist data in a shared container by writing to url provided by FileManager.default.containerURL(forSecurityApplicationGroupIdentifier:) but I don't think you need that for your simple example. If you want to share data that is more complex than String, Int, Array ... make sure to convert it to Data since user defaults cannot handle arbitrary data (even if it's Codable).
Manual Signing
If you use manual signing you just have to do the same step in the developer console starting with registering an app group. After that, add the group to all identifiers' capabilities and recreate all provisioning profiles. From there you should be use similar steps to the ones described above.

Changing language in UWP doesn't change system features language - only on app restart

I have a UWP application.
And i have a need to change locale on the fly, so i have this for language changing:
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = language.FourDigitCode;
ResourceContext.GetForViewIndependentUse().Reset();
ResourceContext.GetForCurrentView();
But there is a problem that system features language doesn't switch ( only after application relaunch ) how can i fix it?
Here is an example:
Now i run this code:
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "lv-LV";
ResourceContext.GetForViewIndependentUse().Reset();
ResourceContext.GetForCurrentView();
The UI gets localized, but system features still remain unlocalized:
But when i restart the app, all is OK:
Any ideas how can i fix it?
I'm afraid there is no fix for this and what you've seen is by design. Ref Remarks of PrimaryLanguageOverride property:
When you set the PrimaryLanguageOverride, this is immediately reflected in the Languages property. However, this change may not take effect immediately on resources loaded in the app UI. To make sure the app responds to such changes, you can listen to the QualifierValues property on a default resource context and take whatever actions may be needed to reload resources. Those requirements may vary depending on the UI framework used by the app, and it may be necessary to restart the app.
For your scenario, a restart is needed. I'd suggest that you can add a tip to tell users to restart the app and also a button to close the app like what used in News App.
And to close the app, we can call Application.Exit method like the following.
Application.Current.Exit();
Maybe page reloading can fix it? Try to re-navigate to the same page.
Found the example below here.
//like this
private bool Reload(object param = null)
{
var type = Frame.CurrentSourcePageType;
Frame.Navigate(type, param);
Frame.BackStack.Remove(Frame.BackStack.Last());
}
// or like this
private bool Reload(object param = null)
{
var frame = Window.Current.Content as Frame;
frame.Navigate(frame.CurrentSourcePageType, param);
frame.BackStack.Remove(frame .BackStack.Last());
}

Custom Grid App

So I am trying to make modifications to the custom grid app that rally has already created. I found the source code at https://github.com/RallyApps/app-catalog/tree/master/src/apps/grid. However, I cannot get that code to work. I have added it to a js and then ran build (I also changed the json). However, when I then add the app to rally it doesn't give me the settings options (object, query, pagesize, etc) and just generates a table. This table generates 4 rows (the number of user stories I have), but the rows are completely blank except for gears at the beginning of each row. I was wondering if I was building this app incorrectly or if I had grabbed the wrong code. If not, is there a place where can I get the complete code or a way to modify the already existing code?
Thanks
You may add a fetch to the config as below:
config: {
defaultSettings: {
types: 'hierarchicalrequirement',
fetch: 'FormattedID,Name'
}
}
and it will display a grid.
It will not display settings dialog however. The source code in this github repo is not exactly the CustomGrid app available from the AppCatalog in the UI. It does not have the full functionality and not ready yet. I submitted a defect.

App works as desired in debug mode but crashes in Rally environment

I have created an app that creates a grid dynamically, as well as lets the user make changes to one of the grid columns via a 'numberfield' editor. Everything is working great in the debug environment but when I try to edit one of the fields in the Rally environment it crashes the app. From the looks of it, the iframe containing the app is just reloading altogether.
Now, here's the weird part that may be a clue to what's going on. The app crashes after I click elsewhere on the app (committing the change) but if I scroll the mouse wheel somewhere on the app, the spinner loses focus (no up/down arrows) and then if I click somewhere the edits are applied and the app doesn't crash. Once again in the debug mode I don't need to go through this, I can just click elsewhere and the changes are applied.
This is a known issue with 2.0p5 that will be fixed with the next release of the SDK. Basically it's using a sledgehammer to respond to the fact that something was edited and refreshing it. Since the new SDK can communicate with the message bus this is totally unnecessary...
In the meantime you should be able to patch your app by defining a global Rally.getApp function that returns your app instance to prevent the hard refresh:
//In your app definition give it an xtype:
Ext.define('My.App', {
extend: 'Rally.app.App',
//...
alias: 'widget.myapp'
//...
});
//Find the app instance by its xtype and return it
Rally.getApp = function() {
return Ext.ComponentQuery.query('myapp')[0];
};
You can then delete that code once 2.0p6 is released and you upgrade.

getting and setting application preferences with the App SDK

How do you store and retrieve application preferences using the App SDK?
I see in some of the scripts they seem to use use:
rallyDataSource.preferences.getAppPreferences()
rallyDataSource.preferences.update()
rally.sdk.data.Preferences.parse()
Are these documented anywhere?
Thanks...
Those functions are for unsupported and undocumented in the AppSDK. We never were able to make the preference functionality simple enough for us to fully include in the AppSdk.
I would recommend saving the Preferences manually.
Here are some things to remember when dealing with preferences.
Preferences require a name and a scoping parameter.
The combination of the scoping and the name must be unique. This code will show you how to save a preference that is name spaced to your current workspace and namespace it by the apps current id. It will not work external to a Rally App tab unless you replace WORKSPACE_OID with a workspace's object id.
var value = { value : true };
rallyDataSource.create("preference",
{
Name: prefNameKey + rally.sdk.util.Context.getAppInfo().getAppId(),
Workspace: "/workspace/__WORKSPACE_OID__",
Value: dojo.toJson(value)
}, function() {
}, function() {
});