Hi All,
Project Requirement:
I need to create a form to update the ownership of objects from a terminated user to a new owner. Each object should display in a row with its description and a dropdown for selecting a new owner, arranged in three columns.
Issues Encountered:
Setting the section type to “text” prevents the dropdown from displaying.
Omitting the section type results in HTML being shown as plain text.
I want to use JavaScript to link the dropdown selections: if the first dropdown is changed, it should apply that value to other fields, but if any field is manually changed, those values should remain.
Request for Guidance:
How can I properly display the objects with the dropdown?
How can I process the selected new owners?
Code Snippet Request: Please include example code to help illustrate the solution.
Thanks for your assistance!
reference image:
Code:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Workflow PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Workflow created="1726576115350" explicitTransitions="true" handler="sailpoint.api.StandardWorkflowHandler" id="c0a8d81b91fe1f648191fff4be960281" libraries="Identity,BatchRequest" modified="1727937321052" name="Owner Update WF Test">
<Variable initializer="string:true" name="trace"/>
<Variable initializer="string:false" name="transient"/>
<Variable input="true" name="launcher"/>
<Variable input="true" name="requester"/>
<Variable input="true" name="targetIdentity"/>
<Variable input="true" name="launcherEmail"/>
<Variable input="true" name="requesterEmail"/>
<Variable input="true" name="targetIdentityEmail"/>
<Variable editable="true" name="newOwner"/>
<Variable editable="true" name="applicationsList"/>
<Variable editable="true" name="managedAttributesList"/>
<Variable editable="true" name="bundlesList"/>
<Variable editable="true" name="selection"/>
<Variable editable="true" name="identityName"/>
<Variable editable="true" name="steward"/>
<Variable editable="true" name="Application Owner"/>
<Variable editable="true" name="Entitlement Owner"/>
<Variable editable="true" name="Role Owner"/>
<Variable editable="true" name="selectionEnt"/>
<Variable editable="true" name="selectionRole"/>
<Variable editable="true" name="manager"/>
<Variable editable="true" name="selectionManager"/>
<Variable editable="true" name="workitemId"/>
<Variable editable="true" name="workitemName"/>
<Step icon="Default" name="PrintInputVariables" posX="145" posY="10">
<Script>
<Source>
// System.out.println("manager = " + manager);
System.out.println("requester = " + requester);
// System.out.println("managerEmail = " + managerEmail);
System.out.println("requesterEmail = " + requesterEmail);
// System.out.println("requesterName = " + requesterName);
</Source>
</Script>
<Transition to="ownerUpdate"/>
</Step>
<Step icon="Default" name="ownerUpdate" posX="444" posY="14">
<Approval name="MRC Ressign a New Owner" owner="ref:launcher" return="newOwner" send="requester,targetIdentity,launcher">
<Arg name="workItemDescription" value="Owner Reassignment for $(targetIdentity)"/>
<Arg name="workItemRequester" value="ref:requester"/>
<Arg name="workItemTargetIdentity" value="ref:targetIdentity"/>
<Arg name="workItemTargetName" value="ref:targetIdentity"/>
<Arg name="workItemState" value="Pending"/>
<Arg name="workItemType" value="Form"/>
<Form name="Owner Reassignment">
<Attributes>
<Map>
<entry key="pageTitle" value="MRC Owner Reassignment Form"/>
</Map>
</Attributes>
<Section name="htmlSection" type="text">
<Field filterString="htmlRender" type="text">
<Attributes>
<Map>
<entry key="contentIsEscaped" value="true"/>
</Map>
</Attributes>
<Script>
<Source>
return "<span style='color:#037DA1;'><strong>Note: This Form is to Update/Reassign a New owner for all objects owned by the Terminated user</strong></span><br><br>";
</Source>
</Script>
</Field>
</Section>
<Section columns="4">
<Field columnSpan="1" displayName="Select User" dynamic="true" filterString="inactive == true" name="userId" postBack="true" required="true" type="identity">
<Attributes>
<Map>
<entry key="valueProperty" value="name"/>
</Map>
</Attributes>
</Field>
</Section>
<Section type="text">
<Field dependencies="userId" displayName="" dynamic="true" multi="true" name="identityDetails" postBack="true">
<Attributes>
<Map>
<entry key="contentIsEscaped" value="false"/>
<entry key="hidden" value="script:return form.getField("userId").getValue() == null;"/>
</Map>
</Attributes>
<Script>
<Source>
import sailpoint.object.Identity;
String userId = form.getField("userId") != null ? (String) form.getField("userId").getValue() : "Adam.Kennedy";
log.debug("UserId from form: " + userId);
String userInfo = "";
try {
Identity user = context.getObjectByName(Identity.class, userId);
if (user != null) {
userInfo += "<table class='spTable'><th style='text-align:center; color:#037DA1' colspan='2'>User Information</th>";
userInfo += "<tr><td><b>Username</b></td><td>" + user.getName() + "</td></tr>";
userInfo += "<tr><td><b>First Name</b></td><td>" + user.getFirstname() + "</td></tr>";
userInfo += "<tr><td><b>Last Name</b></td><td>" + user.getLastname() + "</td></tr>";
userInfo += "<tr><td><b>Manager</b></td><td>" + (user.getManager() != null ? user.getManager().getDisplayName() : "No Manager") + "</td></tr>";
userInfo += "<tr><td><b>Department</b></td><td>" + (user.getAttribute("departmentName") != null ? user.getAttribute("departmentName") : "No Department") + "</td></tr>";
userInfo += "<tr><td><b>Job Title</b></td><td>" + (user.getAttribute("jobTitle") != null ? user.getAttribute("jobTitle") : "No Job Title") + "</td></tr>";
userInfo += "</table>";
} else {
userInfo = "<font color='red'>User not found: " + userId + "</font>";
}
} catch (Exception ex) {
log.error("Error fetching user details", ex);
userInfo = "<font color='red'>Error retrieving user details</font>";
}
return userInfo;
</Source>
</Script>
</Field>
</Section>
<Section columns="4" name="appSingleSec" type="text">
<Field columnSpan="4" dependencies="userId" displayName="Application Objects" dynamic="true" name="ownedObjectsSingle" postBack="true" type="object">
<Attributes>
<Map>
<entry key="contentIsEscaped" value="true"/>
<entry key="hidden" value="script:return form.getField("userId").getValue() == null;"/>
</Map>
</Attributes>
<Script>
<Source>
import sailpoint.object.Application;
import sailpoint.object.QueryOptions;
import sailpoint.object.Filter;
import sailpoint.object.Identity;
import java.util.List;
import java.util.Map;
String content = "";
try {
String userId = form.getField("userId") != null ? (String) form.getField("userId").getValue() : "Adam.Kennedy";
Identity selectedUser = context.getObjectByName(Identity.class, userId);
if (selectedUser != null) {
// Fetch applications owned by the selected user
QueryOptions appQueryOptions = new QueryOptions();
appQueryOptions.addFilter(Filter.eq("owner", selectedUser));
List applicationsList = context.getObjects(Application.class, appQueryOptions);
// Fetch active identities for the New Owner dropdown
QueryOptions queryOptions = new QueryOptions();
queryOptions.addFilter(Filter.eq("inactive", false)); // Filter active identities
List inactiveIdentities = context.getObjects(Identity.class, queryOptions);
// Start building the table content
content += "<table class='spTable' style='width:100%; border-collapse:collapse;'>";
content += "<tr><th style='border:1px solid black;'>Application</th><th style='border:1px solid black;'>Description</th><th style='border:1px solid black;'>New Owner</th></tr>";
if (applicationsList != null && !applicationsList.isEmpty()) {
for (Application app : applicationsList) {
String appName = app.getName();
String description = "No description available";
Map descriptions = app.getDescriptions();
if (descriptions != null && !descriptions.isEmpty()) {
description = descriptions.getOrDefault("en", descriptions.values().iterator().next());
}
content += "<tr>";
content += "<td style='border:1px solid black;'>" + appName + "</td>";
content += "<td style='border:1px solid black;'>" + description + "</td>";
content += "<td style='border:1px solid black;'>";
content += "<select>";
// Loop through the inactiveIdentities and add options
for (Identity identity : inactiveIdentities) {
content += "<option value='" + identity.getName() + "'>" + identity.getName() + "</option>";
}
content += "</select>";
content += "</td>";
content += "</tr>";
}
} else {
content += "<tr><td colspan='3' style='border:1px solid black; text-align:center;'>No Applications Found</td></tr>";
}
content += "</table>";
} else {
content = "<font color='red'>User not found: " + userId + "</font>";
}
} catch (Exception ex) {
content = "<font color='red'>Error retrieving applications or identities: " + ex.getMessage() + "</font>";
}
if ("".equals(content)) {
content = "<font color='red'>Please select a user to see the owned applications.</font>";
}
return content;
</Source>
</Script>
</Field>
</Section>
<Button action="next" label="Next"/>
<Button action="cancel" label="Exit"/>
</Form>
<InterceptorScript>
<Source>
import sailpoint.object.Identity;
import sailpoint.object.Configuration;
import sailpoint.object.Workflow;
import sailpoint.object.WorkItem;
import sailpoint.object.WorkItem.State;
if (method.equals(Workflow.INTERCEPTOR_START_APPROVAL)) {
log.error("Method is startApproval");
} else if (method.equals(Workflow.INTERCEPTOR_OPEN_WORK_ITEM)) {
if (item == null) {
log.error("No work item found");
} else {
try {
item.setName("Workitem Form for: " + targetIdentity);
item.setState(State.Pending);
context.saveObject(item);
// log.error("WorkItem saved: " + item.toXml());
String workitemId = item.getId();
String workitemName = item.getName();
workflow.put("workitemId", workitemId);
workflow.put("workitemName", workitemName);
log.error("Current Item Name: " + workitemName);
log.error("Current Item ID: " + workitemId);
log.error("Current Item Name: " + workitemName);
log.error("Current Item State: " + item.getState());
log.error("Current Item targetname: " + item.getTargetName());
log.error("Current Item level: " + item.getLevel());
log.error("Current Item type: " + item.getType());
log.error("Current Item requester: " + item.getRequester());
} catch (Exception e) {
log.error("Exception while saving WorkItem: " + e.getMessage(), e);
}
}
} else {
log.error("Method does not match startApproval or openWorkItem");
}
</Source>
</InterceptorScript>
</Approval>
<Transition to="End"/>
</Step>
<Step icon="End" name="End" posX="708" posY="30"/>
</Workflow>