Literal parameters and multiple users

fc
New Contributor III

Hi all, 

I'm currently developing a dashboard that will likely be used by multiple users at the same time. 
Users will be able to set some initial parameters within the dashboard, and click on a button that will trigger a BR that will return some output rows within a table in the database. 
After the process is complete, the user will be able to see the output rows through the following SQL Table Editor:

fc_0-1687513687144.png

the parameters that you can see in the "Where Clause" are literal parameters that are set from within the BR when it is triggered by the user (using BRApi.Dashboards.Parameters.SetLiteralParameterValue()), and their value depend on the initial parameters that the user selected in the dashboard.

The problem is, I saw in some posts within the forum that literal parameters are "common" to all users, so every time one user will click the button and launch the process, the literal parameters will be changed. This is a problem, because we expect users to use the dashboard simultaneously. 
Is there a workaround that does not use literal parameters? Or is there a way to make literal parameters "unique" to every user?

 

Thanks in advance!

1 ACCEPTED SOLUTION

RobbSalzmann
Valued Contributor

Literal Parameters values are application-wide, session inspecfic.  Things like formats and colors work well in Literal parameters 

RobbSalzmann_1-1687546284465.png

 

For user/session specific parameters, use Input Parameters:

RobbSalzmann_2-1687546376131.png

In your code, these Input Parameters are oddly named "ModifiedSubVars".  You change the value of the ModifiedSubVars on the returned Task Result object, e.g.  XFLoadDashboardTaskResult, XFSelectionChangedTaskResult depending on what event you're handling.  Be sure to also set one or all of the ChangeCustomSubstVarsIn properties to True.

E.g. 

selectionChangedTaskResult.ChangeCustomSubstVarsInDashboard = True
selectionChangedTaskResult.ModifiedCustomSubstVars.Add("pm_myParameter_Name", "User Specific Value")

View solution in original post

16 REPLIES 16

Omkareshwar
Contributor II

Hi fc,

 

You can set user text property and fetch that value rather than a literal value parameter. 

Dim objUserInfo As UserInfo = BRApi.Security.Admin.GetUser(si, si.UserName)
objUserInfo.User.Text4 = "Setyour value"
Brapi.ErrorLog.LogMessage(si, objUserInfo.User.Text4)

Thanks, Omkareshwar

Archetype Consulting 

Thanks, Omkareshwar
Archetype Consulting

You can also try using:

BRApi.State.GetUserState
BRApi.State.SetUserState

 

ChristianW
Valued Contributor

We are mainly using SetLiteralParameter to store options that should be valid for everybody, like security settings or some basic information like top member nodes, we are not using literal parameters to do anything dynamic or session dependent.

For this purpose, we have all other parameters with 'Input Value' being the most generic.

You can set these dynamic parameters using 'Dashboard Extender' business rules and depending on the use case these two objects XFLoadDashboardTaskResult (for LoadDashboard activities)

Dim loadDashboardTaskResult As New XFLoadDashboardTaskResult()

and XFSelectionChangedTaskResult (actions triggered by dashboard objects)

Dim selectionChangedTaskResult As New XFSelectionChangedTaskResult()

Both own one (load: ModifiedCustomSubstVars) or two (selection: ModifiedCustomSubstVars and ModifiedCustomSubstVarsForLaunchedDashboard) dictionaries you can use to change parameter values.

with

return loadDashboardTaskResult 

or

return selectionChangedTaskResult

you activate the changes.

if you create a new business rule, you get basic samples for these objects:

Case Is = DashboardExtenderFunctionType.LoadDashboard
	If args.FunctionName.XFEqualsIgnoreCase("TestFunction") Then
		
		'Implement Load Dashboard logic here.
		
		If args.LoadDashboardTaskInfo.Reason = LoadDashboardReasonType.Initialize And args.LoadDashboardTaskInfo.Action = LoadDashboardActionType.BeforeFirstGetParameters Then
			Dim loadDashboardTaskResult As New XFLoadDashboardTaskResult()
			loadDashboardTaskResult.ChangeCustomSubstVarsInDashboard = False
			loadDashboardTaskResult.ModifiedCustomSubstVars = Nothing
			Return loadDashboardTaskResult
			End If
	End If

Case Is = DashboardExtenderFunctionType.ComponentSelectionChanged
	If args.FunctionName.XFEqualsIgnoreCase("TestFunction") Then
		
		'Implement Dashboard Component Selection Changed logic here.
		
		Dim selectionChangedTaskResult As New XFSelectionChangedTaskResult()
		selectionChangedTaskResult.IsOK = True
		selectionChangedTaskResult.ShowMessageBox = False
		selectionChangedTaskResult.Message = ""
		selectionChangedTaskResult.ChangeSelectionChangedUIActionInDashboard = False
		selectionChangedTaskResult.ModifiedSelectionChangedUIActionInfo = Nothing
		selectionChangedTaskResult.ChangeSelectionChangedNavigationInDashboard = False
		selectionChangedTaskResult.ModifiedSelectionChangedNavigationInfo = Nothing
		selectionChangedTaskResult.ChangeCustomSubstVarsInDashboard = False
		selectionChangedTaskResult.ModifiedCustomSubstVars = Nothing
		selectionChangedTaskResult.ChangeCustomSubstVarsInLaunchedDashboard = False
		selectionChangedTaskResult.ModifiedCustomSubstVarsForLaunchedDashboard = Nothing
		Return selectionChangedTaskResult
	End If

 

The property names should be self explanatory.

I hope this helps and cheers

Christian

Omkareshwar
Contributor II

You can also create an Ancillary table to store the parameter selection for each user. And fetch those values in your dashboard with this approach you can also save pervious selections made by the user. 

You can opt for any of the approach mentioned the Ancillary table is the preferred one, but it is complex where as |UserText4| is simpler and quickest to implement.

Thanks, Omkareshwar
Archetype Consulting

I wouldn't recommend storing parameters in tables. That is what session variables are for. Please do not create tables when you can use existing functionality.

RobbSalzmann
Valued Contributor

Literal Parameters values are application-wide, session inspecfic.  Things like formats and colors work well in Literal parameters 

RobbSalzmann_1-1687546284465.png

 

For user/session specific parameters, use Input Parameters:

RobbSalzmann_2-1687546376131.png

In your code, these Input Parameters are oddly named "ModifiedSubVars".  You change the value of the ModifiedSubVars on the returned Task Result object, e.g.  XFLoadDashboardTaskResult, XFSelectionChangedTaskResult depending on what event you're handling.  Be sure to also set one or all of the ChangeCustomSubstVarsIn properties to True.

E.g. 

selectionChangedTaskResult.ChangeCustomSubstVarsInDashboard = True
selectionChangedTaskResult.ModifiedCustomSubstVars.Add("pm_myParameter_Name", "User Specific Value")

fc
New Contributor III

Hi Rob,

I tried to use your approach but I did not succeeded. Below a sample of the code I wrote:

Case Is = DashboardExtenderFunctionType.ComponentSelectionChanged

Dim selectionResult As XFSelectionChangedTaskResult=Nothing

If args.FunctionName.XFEqualsIgnoreCase("LaunchAdjustment") Then
..
declare variables
..

selectionResult=Me.AdjustmentProcessMain(.. list of arguments ..)

Return selectionResult

 

 Private Function AdjustmentProcessMain(... list of arguments ...) As XFSelectionChangedTaskResult

Try

Dim selectionChangedTaskResult As New XFSelectionChangedTaskResult()
selectionChangedTaskResult.ChangeCustomSubstVarsInDashboard = True

selectionChangedTaskResult.ModifiedCustomSubstVars.Add("p_RowEntityList","test")
selectionChangedTaskResult.ModifiedCustomSubstVars.Add("p_RowAccList","test1")
selectionChangedTaskResult.ModifiedCustomSubstVars.Add("p_RowDocList","test2")

Body of the function
...
...
...

Return selectionChangedTaskResult

 

 The script is triggered when the user clicks on a button, and (as shown above) I expect the three Input Value parameters (p_RowEntityList, p_RowAccList, p_RowDocList) to be assigned some values (some random strings in this case). 

Nevertheless, when the script is triggered, the underlying process runs fine, but the parameters are not populated. 
What am I doing wrong?

 

If you need additional details please let me know! Thank you

ChristianW
Valued Contributor

You can only see the values, if you embed them in an object or, in the design mode:

ChristianW_0-1687798913996.png

 

@ChristianW that tooltip tidbit is a great one! 😎

RobbSalzmann
Valued Contributor

A couple of things... I usually set the following properties on the XFSelectionChangedTaskResult object:
selectionChangedTaskResult.IsOK = True
selectionChangedTaskResult.ShowMessageBox = False

Also, how are you checking that params are being set? IOW, how do you verify they are being set?

One way sure way to do it is create a text box and set one of your params to the Textbox's Bound Paramater, then put the textbox temporarily on the dashboard

also keep in mind to get the value of the params in another BR, like using another button, you have to send them in as arguments {MyRule}{AnotherFunction}{RowEntityList=|!p_RowEntityList!|, RowAcctList=|!p_rowAccList!|}

Within the main or AnotherFunction that takes a DashboardExtenderArgs parameter args, extract those values:
Dim rowEntityList As String = args.NameValuePairs("RowEntityList", String.empty)
Dim rowAccList As String = args.NameValuePairs("RowAccList", String.empty)

fc
New Contributor III

It works now! Thank you all for the help.
The problem seemed to be that I was not embedding the parameter in any of the components that are present in the dashboard like Christian suggested. 
After embedding the 3 parameters in 3 different Label components and placing the Label components anywhere within the dashboard, the process started working as supposed, and the parameters are now correctly populated. 
One last thing, though, is that now every time the dashboard is refreshed, a popup window appears showing the current value assigned to each of the 3 parameters:

fc_0-1687871461965.png

I believe that's because the parameters are Input parameters.

Is there a way to get rid of it?

 

RobbSalzmann
Valued Contributor

Something isn't getting set in the BR.  This is tricky to troubleshoot.  If all params are set in the BR, you should not get this dialog.  Sometimes its a misspelling or param in the wrong place or forgetting something in the code.  Post your BR code if you want a second set of eyes on it.

fc
New Contributor III
Public Function Main(...arguments...) As Object
Try

Select Case args.FunctionType

Case Is = DashboardExtenderFunctionType.LoadDashboard
If args.FunctionName.XFEqualsIgnoreCase("LoadFunction") Then
.....
End If

Case Is = DashboardExtenderFunctionType.ComponentSelectionChanged
Dim selectionResult As XFSelectionChangedTaskResult=Nothing

If args.FunctionName.XFEqualsIgnoreCase("LaunchAdjustment") Then
...
selectionResult=Me.AdjustmentProcessMain(...arguments...)
Return selectionResult
End If
End Select
Return Nothing

Catch ex As Exception
Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
End Try
End Function


Private Function AdjustmentProcessMain(..arguments..) As XFSelectionChangedTaskResult
Try
Dim selectionChangedTaskResult As New XFSelectionChangedTaskResult()
selectionChangedTaskResult.ChangeCustomSubstVarsInDashboard = True
...
Dim paramchange As New XFselectionchangedtaskresult()
paramchange = Me.AssignOutputParams(si)     'This is the function within which the parameters are assigned a value
.....

Dim Checkresult As String = "... string that pops up when process completed..."
Dim messageresult As New XFselectionchangedtaskresult()
messageresult = Me.ShowMessage(si,Checkresult)
selectionChangedTaskResult.IsOK = messageresult.IsOK
selectionChangedTaskResult.ShowMessageBox = messageresult.ShowMessageBox
selectionchangedtaskresult.Message = messageresult.Message
selectionChangedTaskResult.ModifiedCustomSubstVars = paramchange.ModifiedCustomSubstVars

Return selectionChangedTaskResult

Catch ex As Exception
Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
End Try
End Function


Private Function AssignOutputParams(ByVal si As SessionInfo) As XFSelectionChangedTaskResult
Try
Dim selectionChangedTaskResult As New XFSelectionChangedTaskResult()
Using
... define variables to be assigned to parameters ...
selectionChangedTaskResult.ModifiedCustomSubstVars.Add("p_RowEntityList",Entity_Param_List)
selectionChangedTaskResult.ModifiedCustomSubstVars.Add("p_RowAccList",Acc_Param_List)
selectionChangedTaskResult.ModifiedCustomSubstVars.Add("p_RowDocList",Doc_Param_List)

End Using
Return selectionChangedTaskResult

Catch ex As Exception
Throw ErrorHandler.LogWrite(si,New XFException(si,ex))
End Try
End Function

Private Function ShowMessage(...arguments...) As XFSelectionChangedTaskResult
Try
Dim selectionChangedTaskResult As New XFSelectionChangedTaskResult()
selectionChangedTaskResult.Message= StringHelper.FormatMessage("...message string...")
'Show Message box that the file was processed
selectionChangedTaskResult.IsOK=True
selectionChangedTaskResult.ShowMessageBox= True
Return selectionChangedTaskResult

Catch ex As Exception
Throw ErrorHandler.LogWrite(si,New XFException(si,ex))
End Try
End Function

 I copied here the relevant parts of the BR.
The function that is triggered when the user clicks on the button is AdjustmentProcessMain, within it the function AssignOutputParams is called, and that is where the parameters are assigned a value.

 

Thanks again for the help, much appreciated!!

RobbSalzmann
Valued Contributor

You're getting there.  Use the same TaskResult for everything instead of creating new instances of it.  

RobbSalzmann_0-1687875253225.png

 

RobbSalzmann
Valued Contributor

Try this:

 

Namespace OneStream.BusinessRule.DashboardExtender.testvb
  Public Class MainClass
    Public Function Main(si As SessionInfo, globals As BRGlobals, api As Object, args As DashboardExtenderArgs) As Object
      Dim taskResult As XFSelectionChangedTaskResult = Nothing
      Try
        Select Case args.FunctionType
          Case Is = DashboardExtenderFunctionType.LoadDashboard
            If args.FunctionName.XFEqualsIgnoreCase("LoadFunction") Then
                'Do load stuff
            End If
          Case Is = DashboardExtenderFunctionType.ComponentSelectionChanged
            If args.FunctionName.XFEqualsIgnoreCase("LaunchAdjustment") Then
              taskResult = ProcessAdjustments(si)
            End If
        End Select
        Return taskResult
      Catch ex As Exception
        Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
      End Try
    End Function

    Private Function ProcessAdjustments(si As SessionInfo) As XFSelectionChangedTaskResult
      Dim Entity_Param_List As String = String.Empty
      Dim Acc_Param_List As String = String.Empty
      Dim Doc_Param_List As String = String.Empty
      Dim taskResult As XFSelectionChangedTaskResult = Nothing

      Try
        taskResult = New XFSelectionChangedTaskResult()
        ' do adjustment stuff that assigns the above declared strings.
        taskResult.ChangeCustomSubstVarsInDashboard = True
        taskResult.IsOK = True
        taskResult.Message = String.Empty
        taskResult.ModifiedCustomSubstVars.Add("p_RowEntityList", Entity_Param_List)
        taskResult.ModifiedCustomSubstVars.Add("p_RowAccList", Acc_Param_List)
        taskResult.ModifiedCustomSubstVars.Add("p_RowDocList", Doc_Param_List)
      Catch ex As Exception
        Throw ErrorHandler.LogWrite(si, New XFException(si, ex))
      End Try

      Return taskResult
    End Function
  End Class
End Namespace

 

 

 

 

 

 

fc
New Contributor III

It finally works! The problem was that the popup came out every time the dashboard refreshed, thus every time this section of the script was triggered:

    Case Is = DashboardExtenderFunctionType.LoadDashboard
If args.FunctionName.XFEqualsIgnoreCase("LoadFunction") Then
.....
End If

I managed to avoid the pop up to come out by adding a couple of lines of code:


Case Is = DashboardExtenderFunctionType.LoadDashboard
If args.FunctionName.XFEqualsIgnoreCase("LoadFunction") Then

loadDashboardTaskResult.ChangeCustomSubstVarsInDashboard = True

If Not(args.LoadDashboardTaskInfo.CustomSubstVarsFromPriorRun.XFGetValue("p_RowEntityList").Equals("None")) Then

loadDashboardTaskResult.ModifiedCustomSubstVars.Add("p_RowEntityList", args.LoadDashboardTaskInfo.CustomSubstVarsFromPriorRun.XFGetValue("p_RowEntityList"))

loadDashboardTaskResult.ModifiedCustomSubstVars.Add("p_RowAccList", args.LoadDashboardTaskInfo.CustomSubstVarsFromPriorRun.XFGetValue("p_RowAccList"))
loadDashboardTaskResult.ModifiedCustomSubstVars.Add("p_RowDocList", args.LoadDashboardTaskInfo.CustomSubstVarsFromPriorRun.XFGetValue("p_RowDocList"))

Return loadDashboardTaskResult

Else

loadDashboardTaskResult.ModifiedCustomSubstVars.Add("p_RowEntityList", "None")
        loadDashboardTaskResult.ModifiedCustomSubstVars.Add("p_RowAccList", "None")
        loadDashboardTaskResult.ModifiedCustomSubstVars.Add("p_RowDocList", "None")

Return loadDashboardTaskResult

End If
End If

 The rest of the script is structured as Rob suggested.

Thank you all for the help!