Is it possible to set an Actions submission criteria that prevents submission if an object has more than a certain number of linked objects? - palantir-foundry

I currently have an action that creates a new link between an object of type A, named OA, and an object of type B, named OB.
Our workflow has a constraint such that any object of type B can at most, be linked to 4 objects of type A. As such, I would like to define a submission criterion in the action such that submission is blocked if OB is already linked to 4 objects of type A.
I couldn't find a straightforward way to do this using the Action configuration UI. How could I accomplish this?

The easiest way to accomplish this would be to turn your action into a function backed action. This would allow you to take the following steps to accomplish the desired functionality:
You can search around to all objects of type A that are linked to OB by writing something like:
// Search around to all objects of type A that are linked to OB
const linkedObjects = OB.objectTypeA.all();
// Now get the number of linked objects
const numLinkedObjects = linkedObjects.length;
Prevent the function from running by throwing a UserFacingError if there are more than 4 linked objects
if (numLinkedObjects >= 4) {
throw new UserFacingError("Objects of type B cannot be linked to more than 4
objects of type A");
}
For reference, here are some relevant pages in Foundry’s documentation:
Creating Function Backed Actions (https://www.palantir.com/docs/foundry/action-types/function-actions-getting-started/#getting-started)
Accessing link types in Functions (https://www.palantir.com/docs/foundry/functions/api-objects-links/#link-types)
Throwing UserFacingErrors from Functions (https://www.palantir.com/docs/foundry/functions/user-facing-error/)

While you can certainly do this in a Function-backed action, the tradeoff is that you won't get up front validation of the criteria, but rather the user will submit the action and then will received a toast showing the UserFacingError text. So while this technically achieves the validation, it is a sub-par user experience compared to disabling the button with a message or otherwise catching the condition upstream of the action itself in the workflow.
An alternative, iff you're using the action exclusively through Workshop, (this won't work if you want the action to "stand alone" in object explorer), you can create an object set variable that holds the result of the search around and pass that in as a hidden parameter to the Action. You can then set up the Action submission criteria as normal to check the length of that parameter and provide a message back to the user. You can also use that information in the app itself to, for example, conditionally show or hide some other workflow for the condition.
If you take this approach, make sure to add the hubble-oe:hide-action typeclass to one of the object parameters in the Action Form configuration so that the Action doesn't show up where users could use it through Object Explorer.

Related

How can I configure an action that creates a variable number of objects?

I am looking to create an action type that can be used to create a variable number of objects of a given object type. In other words, a user should be able to use this action to create 3 objects at once, 5 objects at once, etc.
I tried to accomplish this using the action configuration UI in OMA, but ran into the following issues:
I noticed that in the “Rules” section, it is only possible to define a static number of objects to be created. In the example shown in the screenshot below, you’d only be able to create 2 objects rather than a variable number.
Similarly, there is no way to specify a variable number of parameters in the “Form” section, which would be necessary to capture the primary keys for each object the user would like to create. I thought of specifying a string parameter that takes in multiple values as an alternative, but that wouldn’t work because there is no way to assign a single value from this parameter to an object property.
How should I go about accomplishing this?
It would be possible to create a variable number of objects using a function backed action! In particular, you could take the following steps:
Create a new function that takes in a list of primary keys as input and creates an object for each primary key in the list. The code for this function could look something like this:
#Edits(ObjectA)
#OntologyEditFunction()
public createMultipleObjects(primaryKeys: string[]): void {
// Loop through pkeys and create a new object for each pkey
primaryKeys.forEach(k => {
Objects.create().objectA(k)
});
}
You can also reference the following documentation for more guidance on how to define Ontology edit functions.
Create an action in OMA that calls the function that you defined in step 1. You will need to define a multi-value string parameter for this action, which will be passed as an input to the function.
You can refer to the following documentation (https://www.palantir.com/docs/foundry/action-types/function-actions-getting-started/) for a step by step guide on how to configure a function backed action.

how to catch event in codes after linking events in an array of string inside “events” properties of form object variable in dynamic 4D form?

It's easy to catch events from 4D object's methods of 4D binary form (traditional 4D form) but didn't find any clue to do this in the json dynamic form.
I already gave a try with some 4D commands (CALL FORM, CALL WORKER or POST OUTSIDE CALL) as well to install a project method for a form side by side in a new process inside a loop where I handled events inside that project method. But couldn't get around it. Also I couldn't find any solution/example for this in kb or 4D blog or anywhere.
So any example or database template would be more helpful.
Ravi,
Simply string them in an array named "events".
The docs are your friend for things like this: 4D Manual/Dynamic Forms#Events
The "events" property accepts a JSON array (collection) of strings or
numbers. To call an event, enter the event's name or value (see form
event constant values). For exemple, "events":["onLoad"]) or
"events":[1]
I don't know if you can mix the literal and numeric references. I would expect so but haven't actually tested that.
Edit:
Ravi, if by "catch events in code" you mean have the form you've dynamically created respond to them then you will need to include the name of a project method in the "method" tag. You can't just write some code into an object when you build it dynamically, like you can in regular 4D, but you can call a project method. In that method you can use a Case of statement to test the Form event function to determine which event fired and respond appropriately.
You can't pass parameters to this method. But you can use Object get name or Object get pointer commands to determine the particular object that called it.
For example, let's say I include myMethod as the method. The code for myMethod might look like this:
Case of
:(Form event=On Clicked) // on Clicked is a 4D constant
// do something
:(Form event=on Data Change)
// do something else
End case
Or
Case of
:(Object get name(Object current)="myButton")
Case of
:(Form event=on Clicked)
...
End case
:(Object get name(Object current)="anotherName")
Case of
:(Form event=on Clicked)
...
End case
End case
This illustrates two approaches: 1) you write a separate method for each object or 2) write a single method and determine which object called it. I prefer #2 but that's strictly my opinion.

RXSwift eventlistener

I´m kind of new to the reactive pattern and now I have my first bigger question.
I have done a few asychronous requests in the reactive way. But what I wan´t to do now is a "Eventlistener".
I have a Session object, at the moment I have an SessionEventListener protocol. The Session has a list of listeners and informs all of them about a successfull login and an logout. This Listeners can subscribe and unsubscribe. This thing I want to create reactive now.
How would you do that?
My Idea is to define a BehaviourSubject:
public let loginEventBehaviourSubject = BehaviorSubject(value: true)
now I can send onNext true if the session logged in, and false if it was logged out:
loginEventBehaviourSubject.onNext(true) // on login
loginEventBehaviourSubject.onNext(false) // on logout
And my "listeners" can subscribe to it.
But I would prefere to have subjects for every event:
public let loginEventBehaviourSubject = BehaviorSubject(value: )
public let logoutEventBehaviourSubject = BehaviorSubject(value: )
But then I wouldn´t need the bool. Can I make a kind of "empty" Subject, that only fire "events" without submitting really data.
And then my last question:
Why do I have to add an instance to the initializer of the Subject. Why can´t I create it like: BehaviourSubject<Bool>()?
You need to give an initial value to behavior subject because of it's API. Indeed, it defines BehaviorSubject<T>.value() method, which returns a T. And it would not make sense to call value without a proper initial value. In the presented case, I think PublishSubject is a better representation of the task at hand. You can find more documentation on the available kinds of subjects on the reactivex website.
If you are only interested in the .next event of your subjects, you can do let loginSubject = PublishSubject<Void>() (using behavior subject, you could have written BehaviorSubject<Void>(value: ())) and will the be able to call loginSubject.onNext().
Note though that using any subject is often an anti-pattern. Indeed, subject are most of the time intended to bridge from the imperative to the reactive world and you can very often create things like loginEventObservable as a combination of other observables. For more information on this, I recommend reading To Use Subject Or Not To Use Subject?. It is written using the .Net implementation of Rx, but the theory stays the same.

Yii2: Proper Structuring of Actions based on User Roles

I'm quite worried with the current way I structure actions in my controllers.
I'm not sure which is the more adopted method for implementing actions that show different things for different users based on their type.
For example:
Creating a Model when User is Type 1 uses the same action but passes more parameters to the view than User Type 2.
Creating a Model when User is Type 2 uses same action but passes less parameters to the view and hence there are if statements in the view to show/hide fields based on the User Type.
Is this a proper way of doing things? If not, can you direct me to some documentation that explains a good structure?
Thanks & appreciate your help.
A simple but trival way is this
you can pass an array (eg $param) and then evaluate the type for do the right thinghs inside your action
public function actionYourAction( $param)
{
$type = $param['type'];
switch($param['type']){
case 'TYPE1' :
....
break;
}
a more clean solution could be a proper object oriented class method specialization for user object, instantiate the proper user object where you nedd and pass thsi in action call. Inside the actione simply use the object (specilized) method .

Validate DataGridColumn cells individually

How can I validate the cells in a DataGridColumn individually? (ActionScript 3.5) The validation is configured per-cell, based on fields in the given row. For example
FIELD VALUE TYPE
age 13 Integer
height 13x3 Integer
registered true Boolean
temperature 98.G6 Float
In this case, of course 13x3 and 98.G6 would be invalid.
It's easy to write a Validator ; and to access the data provider objects.
But how do I get individual access to the GUI cell objects so I can set the errorString on an individual cell, either directly or through a Validator?
The itemRenderer/ TextInput control is re-used across the cells for performance reasons, so accessing the GUI-level objects is tricky.
Edit
Answers:
One way to validate and display the invalidation markings, but not per-cell, is to validate all data-provider objects and then set the errorString on the entire grid.
One way to validate per-cell is on the itemEditEnd event handler. (See these pages A B C D). One disadvantage is that it only allows access to the cells from the "inside", not in an action that validates the grid on command.
A custom itemRenderer is another possibility, as in the answer below, but like 3 above, it only allows access to the cells from the "inside", not in an action that validates the grid on command.
See Richard Haven's answer below.
And here's how to access the GUI objects: The list of relevant GUI objects is a protected field; so you can access it by subclassing, then iterate over the GUI-components which represent the cells and set the errorString on each one.
This website at BigResource asks how to access an individual cell. The third post answers there question and provides a link to a better resource than this. Figured you would want both. Hopefully this helps.
If you are looking for arbitrary validation (e.g. on a button or page navigation) rather than immediate navigation (e.g. on cell exit or end-of-edit), then the data is in the underlying dataProvider. I would do validations there rather than dig around inside the grid.
You can add a flag to the data item so the item renderer displays it as an error (or use an external list to flag it).
Cheers
Are you sure you actually want to access the individual cells' DisplayObjects? The component manages instances so that it only creates as many as it needs to display (so that huge datasets don't require a huge number of DisplayObjects on screen).
I think a better alternative would be to provide your DataGridColumn with a custom itemRenderer. You can write this class to accept a validator and update its appearance, and there are a bunch of great tutorials around about that.