Skip navigation
All People > Prashank Singh > Prashank Singh's Blog

With increasing adaptability towards new UI, a lot of users are also bumping into the issues in New UI because of the limitations it has. Where New UI seems to be promising to be used for macro management, we still need to grill into classic PPM for the micro management. However, blending these two UI together might not prove to be the best solution. The reason is the level of expectations by the users for the new UI as per the customization in classic UI in their organization. Also, few elements of new UI are not mature as they are expected to improve by every release.

 

This raises a question as what should be an optimal approach towards UI release. The definition of optimal varies from organization to organization and on the module being rolled out and the customizations being done to classic.

 

One good solution would be to follow an iterative methodology, where we roll out some features to stakeholders & limited users and based on the feedback, revisit previous steps with some improvement and finally making it available for wider audience.

Following steps can be helpful while rolling out the New UI.

 

Step 1a: Access Control for Module control 

Mature way would be not to rush into exposing all modules to wider audience as this would lead to users facing difficulty with adaptability. For any of the mature implementations in classic, the user might tend to compare for more functionality, which is not present in New UI yet. That might be in pipeline on new UI for future release. Now that we understand as all modules all together might not be an ideal solution while launching new UI, next big thought that arises is which module to pick and how to hide other module links. This leads us to Access Control provided by CA for controlling all these modules, one must carefully go through these.

 

For basic setup following list might be helpful:

 

1) Enable REST API from CSA 

 

 

2) Enable Timesheet UI 

 

 

3) Enable Timesheet UI individually by restricting access via Classic CA PPM.

4) Access Control for Project, Staffing  and other elements as per the need and feedback from limited users.

5) Creation of Menu Link to switch between both the UIs.

  

Step1b: Timesheet module, might be your savior of the day

Timesheet module will be nice to start with as this module is least customized as far as user interface go and any other process/java validation stuff will work almost as similar as it works in classic. So, less modification and quick to start for wider audience to accumulate user responses on the behavior of new UI. 


Step2: Kicking other modules, utilizing them carefully  

This step requires a detailed analysis and understanding of each module and try to bridge gaps between any missing functionality which could be there in classic as OOTB or as a custom item specific to your organization. One of the way would be to use links in the project module for solving any issues around dynamic html page, Classic CA PPM link or Jasper report in case of dashboard like view.

This will ensure you that any missing functionality which you have built in classic is one click away. Also you need to make sure to give a way to link it back to either classic r to new UI.


Step3: CSS Can be magical to blend both UI's

Changes to your classic UI to look a bit similar to that of new UI by changing the CSS in classic can work really magical.

This will not leave your user in the impression of using two different systems for PPM and the switching between the UIs will not be hurdle to work with.


Step4: Setting Right Expectation for User

With each release, set context on what to expect in new UI and how to use the modules. Giving them the idea of what they might get in the next release would make their perception positive about the New UI.

 
Step5: The Last one

Direct modification of UI might be a powerful approach to achieve almost anything to mitigate the impact of using different UIs. However,  you need to be aware over this as any modification directly to the .war file used to load new UI is not supported by CA. So, this should be your last step and be avoided.

 

However, if you are still looking for change then below steps for changing a User Value 1 label might be helpful.

 

For changing label "User value 1"  in new UI, the file and its path are as below:

 

1) First you have to identify a .war file placed in CA PPM server folder, war file name: ppm-ux.war

               War file location: %CAPPM_Home_Path%\META-INF\uif\wars

2) Copy and  extract this war file in your machine. Below is a sample of extract for War file

 

3) Look for a localization file path as below: 

               ppm-ux\i18n\en\timesheet.json

4)  You need to change the column definition for the label "User Value 1" which you want to change, will look as below:

                 "user_lov1": "Modified User Value 1",

 5) Then make a .war file again with the modifications included. Then you need to redeploy all the services. You will be able to see the new changed label for the field.

 

One challenge that I have faced while updating .war file is minimized file generation for JavaScript. For any major change in JavaScript for any module, we need to generate minimized file and that needs to be compatible with CA's. For that you must decide which tool to use to extract and generate the .war file. To avoid that scenario, you can change script path from min.js file to relevant .js file in integration.html.

Warning again: This is not supported by CA.

Hope this might have helped few in achieving transition to new UI.

Don't forget to share you challenges and the way you took to overcome those. 

We have already observed the power of D3.js visualization in my previous blog D3.js visualization with Jaspersoft Reporting. Now, question is how to achieve this in Jaspersoft using its in-built component Custom Visualization 

Component also known as CVC. Before we start with CVC component, I will suggest you to follow few links Custom Visualization Component for Jaspersoft Studio v5.6.x | Jaspersoft Community or Custom Visualization Component v6.0.x | Jaspersoft Community .

 

So, let’s start with basic steps which we need for this custom visualization to work. I have divided them into 3 parts:

1) Fetch Data From Source to CVC

2) Creating JavaScript for CVC using d3.js

3) CVC Property Configuration for CSS and JS minified files 

 

Fetch Data From Source to CVC

Create a Dataset where you can fetch different columns into Jasper Fields similar to that of Jasper report where we fetch Columns to Fields and then we feed them into Detail Band for Jasper report generation.

Now we are going to feed these Jasper fields to CVC (similar to that of Chart) as shown below:

 

 

 

Creating JavaScript for CVC using d3.js

Now, we have linked our Data Source to CVC. Next step is to fetch this data in JavaScript along with d3.js skill, I have explained basic of it in below sample Script which can be used to build a proper script, we can also use JSFiddle with sample data to check our JavaScript.

 

define(['d3'], function (d3) {

     return function (instanceData) {  
       
        // instanceData is an Array of Item Data Configuration
        //  In this Sample We have only one Item Data defined followed by only one Series which is also an Array of series
        //  Each series array is a JSON Component
        /*  Sample InstanceData as generated from JasperReport

                        "instanceData": {
                        "id": "element1146094337",
                        "series": [
                            [
                                {
                                    "parentId": 0,
                                    "category": 5027005,
                                    "ch_dt_lm": "Gupta, Gaurav",
                                    "ch_manager": "Singh, Prashank",
                                    "subcategory": "PRJ004965 -- Finance Change - krana, From 01/01/2016 to 01/01/2019",
                                    "value": 1,
                                    "DataId": 5027005
                                },
                                {
                                    "parentId": 5027005,
                                    "category": 5027005,
                                    "ch_dt_lm": "S, Paul",
                                    "ch_manager": "Rana, Kritika",
                                    "subcategory": "PRJ004966 -- Finance Change Cluster, From 01/08/2016 to 25/09/2016",
                                    "value": 2,
                                    "DataId": 5027006
                                }
                            ]
                        ],
                        "height": 560,
                        "width": 1000,
                        "isInteractiveViewer": "false",
                        "script_uri": "d3_zoomable_circle_packing.min.js"
                    }

        */

            var series0 = instanceData.series[0];
            var nodes = series0;

        //  use your javascript and d3.js skill
        //  instanceData.id is going to add all svg element to Jasper report, so i have added one sample for that  

        var svg = d3.select("#" + instanceData.id).append("svg")
                        .attr("width", width + margin.left + margin.right)
                            .append("g")
                                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


    };
});

 

 

 CVC Property Configuration for CSS and JS minified files    

Once we have created our JavaScript, then next is to generate minified file from d3.v3.min.js and Our JavaScript which we have created in above step. For generating minified file, add two files 1) d3.v3.min.js 2) buid.js (sample given below) and then click on build all component as shown below:

 

 

Sample Build.js file

({
    baseUrl: '',
    paths: {
          'd3': 'd3.v3.min',
          'd3_zoomable_circle_packing': 'd3_zoomable_circle_packing'
    },
    name: "d3_zoomable_circle_packing",
    out: "d3_zoomable_circle_packing.min.js"
})

 

Next step is to add this minified file and CSS to our CVC component in the form of property, refer to screen shot below:

 

 

After these steps, we can run this report in jasper studio or we can publish this to Jasper Server, however there are few settings which you need to check for successful run. For studio please refer above mentioned links and to enable CVC in jasper server, I have attached a zip file with steps.

 

Wishing you all a very Happy New Year......

Before we drive into integration of jaspersoft and d3.js visualization and finally Running Jaspersoft Report within CA PPM Object, let me answer some questions popping up in our minds like what is D3.js? or Do we have any examples related to D3 visualization? or what are possible ways for achieving these? So, let's start with learning about D3.js with its visualizations.  

 

D3.js (or just D3 for Data-Driven Documents)

is a JavaScript library for producing dynamic, interactive data visualizations in web browsers. It makes use of the widely implemented SVG, HTML5, and CSS standards. 

D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply data-driven transformations to the document. For example, you can use D3 to generate an HTML table from an array of numbers. Or, use the same data to create an interactive SVG bar chart with smooth transitions and interaction.

D3 is not a monolithic framework that seeks to provide every conceivable feature. Instead, D3 solves the crux of the problem: efficient manipulation of documents based on data. This avoids proprietary representation and affords extraordinary flexibility, exposing the full capabilities of web standards such as HTML, SVG, and CSS. With minimal overhead, D3 is extremely fast, supporting large datasets and dynamic behaviors for interaction and animation. D3’s functional style allows code reuse through a diverse collection of official and community-developed modules.

 

There are number of D3.js visualizations, however I have picked few from these.

1) Sequence sunburst 

2) Collapsible Indented Tree

3) Cross Filter

4) Map Projection Distortions

Now, imagine these visualizations in jaspersoft reports when you are trying to make some powerful decision making Dashboards. They can provide a better visualization as compared to traditional charts. So, let's explore how can we see jasper reporting and D3.js working together to give our data more meaningful clay to make your decision brick. 

 

Note: All of these require some basic knowledge of Javascript, html and basics of D3.js API.

 

Possible ways 

1) Calling Jasper Report and D3.js in CA PPM HTML Portlet 

We can use CA PPM html portlet for calling Jasper report and its component by using its integration methods are:

1) Embedding using HTTP API

2) Getting Started with REST Web Service API

3) Getting Started with Visualize.js

Similarly, we can call D3.js library and methods for achieving both in single html page and if you want to integrate both of these inside edit/create view of CA PPM Object then follow HTML Fancy Lookups: Getting Started & HTML Fancy Lookups: Inline List 

 

 

2) Using HTML element from jasper palette

Working with this apporach need a bit of work around, as html component of jasper server has some limitation, however a powerful way for creating html content with some scripting allowed. Due to a lot of limitations and issues while integration this one is least preferred. 

 

 

3) Using CVC element from jasper palette

The custom visualization component is a JasperReport custom component that can be used to display, inside a report, an SVG dynamically generated by using Javascript. The component itself does nothing, in the sense that you need to specify a javascript file that will be used by the custom visualization component in a small html document to produce the specific SVG image. 

 

I have used CVC approach and have come up with below visualization for Project Hierarchy 

1) Interactive Tree Hierarchy 

2) Zoomable Icicle Report

 

now expanding icicle 

 

I will try to answer How to use CVC component of Jaspersoft in upcoming blog, meanwhile please share your feedback on D3.js visualization and type of visualization which you think can improve CA PPM analytic ability.

Sometimes, client wants to push data feed for CA PPM through .xls/.xlsx file, which is generated from any other system. However, we don't have any specific gel tag for reading such files and that becomes a hurdle while achieving this. Only solution for these scenarios is to invoke java code in gel for reading and writing or modifying xlsx documents.

 

I have tried to read xlsx document via gel so that we can understand some basic logic related to these, Please follow comments and logs in script for learning gel as below.

 

Sample GEL Script for reading xlsx as below:

<?xml version="1.0" encoding="UTF-8"?>  
<gel:script xmlns:core="jelly:core" 
            xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary" 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="jelly:util">    
    <!-- *****************************************************************  -->
    <!-- Program:       Read xlsx File                                      -->
    <!-- Object:        NA                                                  -->
    <!-- Step:          Start Step                                          -->
    <!-- Action:        GEL                                                 -->
    <!-- Author:        Prashank Singh,(Pemari Technology Consultant)       -->
    <!-- Version:       1.0.00                                              -->
    <!-- Created On:    02th August 2017                                    -->
    <!-- Modified On:   02th August 2017, Modified By: Prashank Singh       -->
    <!--                                                                    -->
    <!-- Modification History:   Version 1.0.00                             -->
    <!-- Dependencies:   NA
                                                                           -->
    <!-- ****************************************************************** -->
 <core:catch var="SuperException">
    <gel:log> File Location ("G:\Apps\Clarity\Clarity2211\TestExcel Data\TransactionData.xlsx") </gel:log> 
    <core:new className="java.io.File" var="myFile"> 
        <core:arg value="G:\Apps\Clarity\Clarity2211\TestExcel Data\CODA Extract - Random Generated.xlsx"/> 
    </core:new>
    <gel:log> File Size ${myFile.length()} </gel:log> 
    <core:new className="java.io.FileInputStream" var="fis"> 
        <core:arg type="java.io.File" value="${myFile}"/> 
    </core:new>
    <gel:log> Return first sheet from the XLSX workbook  </gel:log> 
    <core:new className="org.apache.poi.xssf.usermodel.XSSFWorkbook" var="myWorkBook"> 
        <core:arg type="java.io.FileInputStream" value="${fis}"/> 
    </core:new>
    <gel:log> Get iterator to all the rows in current sheet </gel:log> 
     <core:invoke method="getSheetAt" on="${myWorkBook}" var="mySheet">
        <core:arg  value="${0}"/>
     </core:invoke>
    <gel:log> Traversing over each row of XLSX file  </gel:log> 
    <core:invoke method="iterator" on="${mySheet}" var="rowIterator"/>
    <gel:log>____________________________________________________________</gel:log>
    <core:while test="${rowIterator.hasNext()}">
        <gel:log> For each row, iterate through each columns </gel:log>
        <core:invoke method="next" on="${rowIterator}" var="row"/> 
        <core:invoke method="cellIterator" on="${row}" var="cellIterator"/>    
        <core:while test="${cellIterator.hasNext()}">
            <gel:log>Get Cell Type ${cell.getCellType()} </gel:log>
            <core:invoke method="next" on="${cellIterator}" var="cell"/>       
            <core:switch on="${cell.getCellType()}">
                <core:case value="${1}">
                    <gel:log>${cell.getStringCellValue()} </gel:log>
                </core:case>
                <core:case value="${0}">
                    <gel:log>${cell.getNumericCellValue()} </gel:log> 
                </core:case>
                <core:default/>
            </core:switch>
        </core:while>
    </core:while>  
</core:catch>
    <core:if test="${SuperException!=null}">
      <gel:log>Super Exception -- ${SuperException}</gel:log>
   </core:if>  
</gel:script>

Similary you can look for implementation of any document write/modifaction via apache poi jar, Do let me know for you feedback or any comment. 

Most of us are still struggling to run the reports as we used to run, when BOxi was still part of CA PPM reporting. Now, BOxi is not part of CA PPM from 14.4 Version. We have started missing the functionality to run BOxi reports via Action Menu from CA PPM Objects or via Link from Object List.

We can still achieve similar functionality, however it needs bit more work as compared to that of earlier BOxi times.

 

Before we go through running Jaspersoft within CA PPM, we need to understand basics of Jaspersoft integration methods.

Jaspersoft integration methods are:

1) Embedding using HTTP API

2) Getting Started with REST Web Service API

3) Getting Started with Visualize.js

 

We are going to use HTTP API for running reports within CA PPM. Let's learn some basics of URL for Jaspersoft report.

 

Jasper URL: <constructing this as below>

Base URL : /reportservice/flow.html?_flowId=viewReportFlow

Report  URL: &reportUnit=/shared/reports/ProjectEffortReport

                        &standAlone=true

                        &ParentFolderUri=/shared/reports

Report Input Parameters:  &ptype=0

                                              &year=2016

                                              &Project_id=5028001&Project_id=5027020&Project_id=5005001&Project_id=5027008

Optional Parameters: &decorate=no

                                       &output=pdf

sample Jasper URL : 

You can create your own Jasper URL and try to run that by hard coding values in input parameter, similarly you can run jaspersoft Dashboard with URL as: 

                                    _flowId=dashboardRuntimeFlow

                                   &dashboardResource=/shared/reports/ProjectDashboard

                                   &hidden_projectId=5028001

 

Note: Report input control should be unchecked for prompting as shown >>

 

 

As we know, how to construct URL for jaspersoft report and Dashboard. We can now go ahead with our CA PPM integration options, like running report from:

                                                     1) Running Report from Action Menu

                                                     2) Running Report via List Link

                                                     3) Running Report via HTML Lookup (Objects Edit/Create/Filter view)

 

Let's talk about first option for running jaspersoft report via Action Menu, we need following elements:

1) New HTML Portlet 

2) New Jaspersoft report 

3) New Portlet Page with Link parameter

4) New Object Link with parameter mapping 

5) New Object Action

 

Step1:

We will start with Portlet Page and Link Parameter. Also, we need to make sure that we are going to pass value to URL from these parameter id and will be fetching these ids to pass into our report. For example, I have created a Portlet Page with Id as JasperReportTest and Parameters as project_id, year_id and ptype_id.

 

Step2:

Now, we will map these values by creating an Object Link. For example, I have created a link and I need to map project_id with Object ID;  year_id and ptype_id with custom attributes. 

 

Step3:

Create New Object Action with type as internal and select Link which you have created. Now, add this action from  Object>Views>Action Menu so that action link is available to run our jasper report.

 

Step4: Create a new html portlet and add that new portlet to page content which you have created above.

 

Since, we have setup everything correctly for sending parameter from CA PPM to url. Now, we can discuss html code, where we are going to capture these report parameters from urls and then feed these parameter values to Jasper report url which we have already tested. Then, these report url will be passed over to html iframe.

 

<!DOCTYPE html>
<html>
<style type="text/css">
 html, body, div, iframe { margin:0;padding:0;}
 iframe { display:block; width:100%; border:none; }
</style> 
   <body>
<script>
var url1 = window.location.href;
 var str1="/reportservice/flow.html?_flowId=viewReportFlow&reportUnit=/shared/reports/ProjectEffortReport&standAlone=true&ParentFolderUri=/shared/reports&ptype=";
var parameter1 =url1.indexOf("&ptype_id=");
var ptype = url1.substring(parameter1 + 10, parameter1 + 17) 
str1 = str1+ptype;

 

var parameter2 =url1.indexOf("&year_id=");
var year_id = url1.substring(parameter2 + 9, parameter2 + 16)
str1 = str1+"&year="+year_id;

 

var parameter3 =url1.indexOf("&project_id=");
var projectid = url1.substring(parameter3 + 12, parameter3 + 19)
str1 = str1+"&Project_id="+projectid;

 

var myiframe =document.getElementById('myiframe');
myiframe.src = str1;
</script>
       <iframe id="myiframe" frameborder="0" border="0" height="600"></iframe>
   </body>
</html>

 

 

Similarly, you can create a link and use that to run jasperreport via image link field from list.

Now, if you are wondering how we can use option 3 i.e via HTML Lookup, please refer to blog HTML Fancy Lookups: Getting Started.

Introduction of REST API has open doors for more powerful and effective way to achieve integration with different applications. We have already gone through CA PPM REST API  overview in previous Blog. In this Blog we will try to consume RESTful URL’s via gel script, so let’s start with basic Project Read and extracting some basic information.

 

We have already used Postman (or similar tool) for testing and gathering infromation which we might need.

One Project Read from Gel

                      URL /projects/{project_internal_id}

                      Method GET

                      Response Document Type application/json

Please follow comments and logs in script for learning gel to call http service, creating connection, fetching responce via input stream and posting request via output stream.

 

First we need to get all Prameters related to CA PPM REST like basic authentication and URL.

1) GEL Script#1: For setting Basic Parameters.

-------------------------------------------------------------------------------- Code Start -------------------------------------------------------------------------------------------------

<gel:script xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:core="jelly:core"
    xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary"
    xmlns:sql="jelly:sql" xmlns:xog="http://www.niku.com/xog"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="jelly:util">
<!-- ***************************************************************************** -->
<!-- Program:       Community Blog                                                        -->
<!-- Object:        NA                                                                               -->
<!-- Step:          Start Step                                                                      -->
<!-- Action:        Set Clarity Parameter                                                  -->
<!-- Author:        Prashank Singh,(Pemari Technology Consultant)      -->
<!-- Version:       1.0.00                                                                          -->
<!-- Created On:    4th June 2017                                                         -->
<!-- Modified On:   5th June 2016, Modified By: Prashank Singh         -->
<!--                                                                                                         -->
<!-- Modification History:   Version 1.1.03                                             -->
<!-- Dependencies:   NA                                                                        -->
<!-- ***************************************************************************** -->
<!--*****************************************************************************  -->
<!-- Set Clarity Parameters -->
<!--*******************************************************************************-->
<core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milStart00"/>

<!-- *** Fetch the clarity's parameter from Property File ***   -->

<core:invokeStatic className="com.niku.union.config.ConfigurationManager" method="getInstance" var="thisClarityConfig"/>

 

<!-- *** Fetch the clarity's Version ***    -->
<core:set value="${thisClarityConfig.getVersionProperty('version')}" var="ClarityVersion"/>

<!-- *** Fetch the clarity's Application URL ***    -->

<core:set value="${thisClarityConfig.getProperties().getWebServer().getWebServerInstance(0).getEntryUrl()}" var="AppEntryUrl"/>
<core:set value="${thisClarityConfig.getProperties().getWebServer().getWebServerInstance(0).getContext()}" var="AppContext"/>
<!-- *** no method for rest context, using gel parameter*** -->
<!--  <core:set value="${thisClarityConfig.getProperties().getWebServer().getWebServerInstance(0).getrestContext()}" var="AppRestContext"/> -->

<gel:parameter
default="/ppm" var="AppRestContext"/>

<core:set value="${AppEntryUrl}${AppContext}" var="ClarityBaseUrl"/>
<core:set value="${AppEntryUrl}${AppRestContext}/rest/v1" var="ClarityRestUrl"/>

<!-- *** Fetch the sender's mail address *** -->

<core:invoke method="getProperties" on="${thisClarityConfig}" var="property"/>
<core:invoke method="getMailServer" on="${property}" var="mailserver"/>
<core:invoke method="getUsername" on="${mailserver}" var="mailsender"/>

<!-- *** Set integration user and password *** -->

<gel:parameter default="true" var="DebugParameter"/>
<gel:parameter default="admin" var="cl_UserName"/>
<gel:parameter default="${thisClarityConfig.getProperties().getApplicationServer().getAdminPassword()}" secure="true" var="cl_UserPassword"/>
<core:if test="${cl_UserPassword==null}"><gel:log level="ERROR">No Password set for user ${cl_UserName}</gel:log></core:if>    
<!-- *** Encoding basic Authorization with Base 64 *** --> 
<core:invokeStatic var="base64" className="com.niku.union.utility.Base64" method="encode"> 
    <core:arg type="java.lang.String" value="${cl_UserName}:${cl_UserPassword}" /> 
</core:invokeStatic> 
<core:set var="basicAuth" value="Basic ${base64}"/>
<!--*****************************************************************-->
<!-- Persist the parameters through the process -->
<!--*****************************************************************-->
<gel:persist scope="INSTANCE" var="ClarityBaseUrl">${ClarityBaseUrl}</gel:persist>
<gel:persist scope="INSTANCE" var="ClarityRestUrl">${ClarityRestUrl}</gel:persist>
<gel:persist scope="INSTANCE" var="cl_UserName">${cl_UserName}</gel:persist>
<gel:persist scope="INSTANCE" var="cl_UserPassword">${cl_UserPassword}</gel:persist>
<gel:persist scope="INSTANCE" var="mailsender">${mailsender}</gel:persist>
<gel:persist scope="INSTANCE" var="ClarityVersion">${ClarityVersion}</gel:persist>
<gel:persist scope="INSTANCE" var="basicAuth">${basicAuth}</gel:persist>
<core:if test="${DebugParameter}">
      <gel:log level="INFO">Clarity Parameter's </gel:log>
      <gel:log level="INFO">ClarityBaseUrl        : ${ClarityBaseUrl} </gel:log>
      <gel:log level="INFO">ClarityRestUrl        : ${ClarityRestUrl}</gel:log>
      <gel:log level="INFO">cl_UserName           : ${cl_UserName}</gel:log>
      <gel:log level="INFO">mailsender            : ${mailsender}</gel:log>
      <gel:log level="INFO">ClarityVersion        : ${ClarityVersion}</gel:log>  
      <gel:log level="INFO">basicAuth             : ${basicAuth}</gel:log>   
</core:if> 
    <core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milEnd00"/>
    <core:set var="elapsedTime"   value="${(milEnd00 - milStart00)}"/>
<core:if test="${DebugTimings}"><gel:log><![CDATA[Time taken by script= ${elapsedTime/1000} sec ]]></gel:log></core:if> 
</gel:script>
--------------------------------------------------------------------------------- Code End ------------------------------------------------------------------------------------------------

 

2) GEL Script#2: GET Project Name and Objective field from CA PPM via REST API.

------------------------------------------------------------------------------- Code Start --------------------------------------------------------------------------------------------------

<gel:script xmlns="http://www.w3.org/2001/XMLSchema"

    xmlns:core="jelly:core"

    xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary"

    xmlns:sql="jelly:sql" xmlns:xog="http://www.niku.com/xog"

    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:util="jelly:util">

    <!-- ******************************************************************************  -->

    <!-- Program:       Community Blog                                                          -->

    <!-- Object:        NA                                                                                 -->

    <!-- Step:          Start Step                                                                       -->

    <!-- Action:        GET CA PPM Project                                                    -->

    <!-- Author:        Prashank Singh,(Pemari Technology Consultant)       -->

    <!-- Version:       1.0.00                                                                            -->

    <!-- Created On:    5th June 2017                                                           -->

    <!-- Modified On:   5th June 2016, Modified By: Prashank Singh          -->

    <!--                                                                                                           -->

    <!-- Modification History:   Version 1.0.00                                               -->

    <!-- Dependencies:   NA                                                                         -->

    <!-- ****************************************************************************** -->

   

    <!--******************************************************************************-->

    <!-- Reading Project Infromation -->

    <!--******************************************************************************-->

   

<!-- *** Please Save Gel Parameter for proejct to fetch *** -->

<gel:parameter default="1" var="cl_ProjectInternalId"/>

<gel:parameter default="true" var="DebugClarity"/>

 

<core:catch var="SuperException">      

<core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milStart00"/>

<gel:log><![CDATA[************ Clarity Project Information Extraction started  *********]]></gel:log>

<core:if test="${DebugClarity}"><gel:log/><gel:log>Basic Auth Encoded 64: ${basicAuth}</gel:log></core:if>

 

<!-- *** Setting REST URL for Getting Project Name and Objective ***    -->

<core:set var="httpRESTURL">${ClarityRestUrl}/projects/${cl_ProjectInternalId}/?fields=objective,name</core:set>

    <core:if test="${DebugClarity}"><gel:log/><gel:log>httpRESTURL: ${httpRESTURL}</gel:log></core:if>

<core:new className="java.net.URL" var="remoteURL" ><core:arg type="java.lang.String" value="${httpRESTURL}" /></core:new>

   

<!-- *** Setting Connection Details *** -->

<core:set var="ClarityConnection" value="${remoteURL.openConnection()}"/>  

<core:expr value="${ClarityConnection.setDoOutput(true)}" /> 

<core:expr value="${ClarityConnection.setDoInput(true)}" />

<core:expr value="${ClarityConnection.setConnectTimeout(180000)}" />

<core:expr value="${ClarityConnection.setReadTimeout(180000)}" />

<core:expr value='${ClarityConnection.setRequestMethod("GET")}'/> 

<core:expr value='${ClarityConnection.setRequestProperty("Content-type", "application/json")}'/>

<core:expr value='${ClarityConnection.setRequestProperty("Accept", "application/json")}'/>         

<core:expr value='${ClarityConnection.setRequestProperty("cache-control", "no-cache")}'/>

<core:expr value='${ClarityConnection.setRequestProperty("Authorization",  basicAuth)}'/> 

<!-- *** Sending Request for Fetching Details from Connection ***   -->         

<core:set var="void" value="${ClarityConnection.connect()}"/>

 

<!-- *** Fetching Responce from Connection ***  -->                

<core:set var="CL_isAuthenticated" value="${ClarityConnection.getHeaderField(0)}" />

<core:set var="response_msg" value="${ClarityConnection.getResponseMessage()}" />

<core:if test="${DebugClarity}"><gel:log>Clarity isAuthenticated: ${CL_isAuthenticated}</gel:log></core:if>

    <core:if test="${CL_isAuthenticated=='HTTP/1.1 200'}">

 

        <!-- *** Reading Input Stream form Connection ***   -->

        <core:set var="httpInputStream1" value="${ClarityConnection.getInputStream()}" />

        <core:new className="java.io.InputStreamReader" var="v_Input1">

            <core:arg type="java.io.InputStream" value="${httpInputStream1}"/>

        </core:new>

        <core:new className="java.io.BufferedReader" var="v_InputData1">

            <core:arg type="java.io.InputStreamReader" value="${v_Input1}"/>

        </core:new>

       

        <!-- *** Responce Saved in Variable for Reading/Modification ***    -->

        <core:set value="${v_InputData1.readLine()}" var="ClarityProjectInfo"/>

        <core:if test="${DebugClarity}"><gel:log>httpData: ${ClarityProjectInfo}</gel:log></core:if>

        

        <!-- *** Closing Input Stream ***   -->

        <core:set var="void" value="${httpInputStream1.close()}" />

       

        <!-- Get JSONObject from response string -->

        <core:new className="org.json.JSONObject" var="J_ClarityPrjInfo" >

            <core:arg type="java.lang.String" value="${ClarityProjectInfo}" />

        </core:new>

       

        <!-- Get the values from response -->

        <core:set var="CL_name"       value="${J_ClarityPrjInfo.get('name')}"/>

        <core:set var="CL_objective"  value="${J_ClarityPrjInfo.get('objective')}"/>

        <core:if test="${DebugClarity}"><gel:log>Clarity Project name: ${CL_name}</gel:log></core:if>

        <core:if test="${DebugClarity}"><gel:log>Clarity Project Objective: ${CL_objective}</gel:log></core:if>

</core:if> 

    <core:if test="${CL_isAuthenticated!='HTTP/1.1 200'}">

        <gel:log><![CDATA[************ Error while reading Project Information *********]]></gel:log>                           

    </core:if> 

        <core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milEnd02"/>

            <core:set var="elapsedTime"   value="${(milEnd02 - milStart00)}"/>

            <gel:log><![CDATA[************ Clarity Project Information Extracted *********]]></gel:log>                            

        <core:if test="${DebugTimings}"><gel:log><![CDATA[Time taken to extract Information= ${elapsedTime/1000} sec ]]></gel:log></core:if>    

 </core:catch>

<core:if test="${SuperException!=null}"><gel:log>Super Exception -- ${SuperException}</gel:log></core:if>

    <core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milEnd00"/>

    <core:set var="elapsedTime"   value="${(milEnd00 - milStart00)}"/>

    <core:if test="${DebugTimings}"><gel:log><![CDATA[Time taken by script= ${elapsedTime/1000} sec ]]></gel:log></core:if> 

</gel:script>

---------------------------------------------------------------------------------- Code End -----------------------------------------------------------------------------------------------

 

Screenshot of GET Method response in GEL Script as below:


Now lets try to create a Project in CA PPM using Restful URL and POST Method. Creating a New Project infromation we might need will be similar as below:

                        URL /projects

                        Method POST

                        Response Document Type application/json 

                        Request Document Type application/json 

                        Response Payload  {  "code": "P0000001",  "name": "ProjectNameChange" }

 

3) GEL Script#3: POSTing Project in CA PPM

------------------------------------------------------------------------------- Code Start --------------------------------------------------------------------------------------------------

<gel:script xmlns="http://www.w3.org/2001/XMLSchema"

    xmlns:core="jelly:core"

    xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary"

    xmlns:sql="jelly:sql" xmlns:xog="http://www.niku.com/xog"

    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:util="jelly:util">

    <!-- ******************************************************************************  -->

    <!-- Program:       Community Blog                                                          -->

    <!-- Object:        NA                                                                                 -->

    <!-- Step:          Start Step                                                                       -->

    <!-- Action:        POST CA PPM Project                                                    -->

    <!-- Author:        Prashank Singh,(Pemari Technology Consultant)       -->

    <!-- Version:       1.0.00                                                                            -->

    <!-- Created On:    5th June 2017                                                           -->

    <!-- Modified On:   5th June 2016, Modified By: Prashank Singh          -->

    <!--                                                                                                           -->

    <!-- Modification History:   Version 1.0.00                                               -->

    <!-- Dependencies:   NA                                                                         -->

    <!-- ****************************************************************************** -->

  

    <!--******************************************************************************-->

    <!-- Creating Project Infromation -->

    <!--******************************************************************************-->

  

<gel:parameter default="true" var="DebugClarity"/>

<core:catch var="SuperException">     

<core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milStart00"/>

<gel:log><![CDATA[************ Clarity Project creation started  *********]]></gel:log>

<core:if test="${DebugClarity}"><gel:log/><gel:log>Basic Auth Encoded 64: ${basicAuth}</gel:log></core:if>

 

<!-- *** Setting REST URL for POSTing Project  ***    -->

<core:set var="httpRESTURL">${ClarityRestUrl}/projects</core:set>

    <core:if test="${DebugClarity}"><gel:log/><gel:log>httpRESTURL: ${httpRESTURL}</gel:log></core:if>

<core:new className="java.net.URL" var="remoteURL" ><core:arg type="java.lang.String" value="${httpRESTURL}" /></core:new>

  

<!-- *** Setting Connection Details *** -->

<core:set var="ClarityConnection" value="${remoteURL.openConnection()}"/> 

<core:expr value="${ClarityConnection.setDoOutput(true)}" />

<core:expr value="${ClarityConnection.setDoInput(true)}" />

<core:expr value="${ClarityConnection.setConnectTimeout(180000)}" />

<core:expr value="${ClarityConnection.setReadTimeout(180000)}" />

<core:expr value='${ClarityConnection.setRequestMethod("POST")}'/>

<core:expr value='${ClarityConnection.setRequestProperty("Content-type", "application/json")}'/>

<core:expr value='${ClarityConnection.setRequestProperty("Accept", "application/json")}'/>        

<core:expr value='${ClarityConnection.setRequestProperty("cache-control", "no-cache")}'/>

<core:expr value='${ClarityConnection.setRequestProperty("Authorization",  basicAuth)}'/>

<!-- *** Sending Request for psodting details from Connection ***   -->        

<core:set var="void" value="${ClarityConnection.connect()}"/>

 

<!-- *** Setting Project creation variable ***   -->    

 <core:set var="CreateProject" escapeText="false">

<![CDATA[{"code": "P0000001",  "name": "ProjectNameChange"}]]>

</core:set>

    <core:new className="java.io.OutputStreamWriter" var="wr1">

      <core:arg type="java.io.OutputStream" value="${ClarityConnection.getOutputStream()}"/>

    </core:new>

        <core:set var="void" value="${wr1.write(CreateProject)}"/>

        <core:set var="void" value="${wr1.flush()}"/>

        <core:set var="void" value="${wr1.close()}"/>

 

<!-- *** Fetching Responce from Connection ***  -->               

<core:set var="CL_isAuthenticated" value="${ClarityConnection.getHeaderField(0)}" />

<core:set var="response_msg" value="${ClarityConnection.getResponseMessage()}" />

<core:if test="${DebugClarity}">

    <gel:log>isAuthenticated: ${CL_isAuthenticated}</gel:log>

    <gel:log>response_msg:  ${response_msg}</gel:log>

</core:if>

    <core:if test="${CL_isAuthenticated=='HTTP/1.1 200'}">

         <gel:log><![CDATA[************ Project Created Successfully *********]]></gel:log>                          

    </core:if>

    <core:if test="${CL_isAuthenticated!='HTTP/1.1 200'}">

        <gel:log><![CDATA[************ Error while reading Project Information *********]]></gel:log>                          

    </core:if>

        <core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milEnd02"/>

            <core:set var="elapsedTime"   value="${(milEnd02 - milStart00)}"/>

    <core:if test="${DebugTimings}"><gel:log><![CDATA[Time taken to extract Information= ${elapsedTime/1000} sec ]]></gel:log></core:if>   

 </core:catch>

<core:if test="${SuperException!=null}"><gel:log>Super Exception -- ${SuperException}</gel:log></core:if>

    <core:invokeStatic className="java.lang.System"   method="currentTimeMillis" var="milEnd00"/>

    <core:set var="elapsedTime"   value="${(milEnd00 - milStart00)}"/>

    <core:if test="${DebugTimings}"><gel:log><![CDATA[Time taken by script= ${elapsedTime/1000} sec ]]></gel:log></core:if>

</gel:script>

------------------------------------------------------------------------------- Code End ---------------------------------------------------------------------------------------------------

 

Similar we can call other methods for operations like Create, Read, Full object Update, Partial Update. Please provide your feedback/comment/concerns over CA PPM REST and GEL Sciprt Consuming these RESTful URLs for health discussion.

 

cappmppm gelgel scriptingca ppm rest apihttp restrest callsppmblog personal post community_blog 

Prashank Singh

CA PPM REST API

Posted by Prashank Singh Champion May 30, 2017

With Version 14.3 CA has introduced new web service i.e. REST API for resource retrieving and modifying PPM data, this new web service is powerful to achieve integration with other application, interactive interfaces, easy business automation and other stuff, before these advance development we need to first understand how to use them. So lets get started with CA PPM's new web service Authentications, resource data access and some basics. 

 

REST API URL:

URL structure to access the REST APIs: https://<hostname>:<port>/<context>/rest/<api-version>/<resource-name>

Examplehttps://samplehost:8080/ppm/rest/v1/projects

Where

  • ppm is the default web context for the REST APIs

  • "v1" is the only supported API version for the current release

  • projects is the CA PPM object that the REST API is accessing 

 

Resource and Operations (Version 15.2):

  • Create, update, or retrieve projects
  • Create, update, retrieve, or delete tasks
  • Create, update, retrieve, or delete teams
  • Create, update, retrieve, or delete assignments
  • Retrieve resources
  • Create, update, retrieve, or delete timesheets, time entries, timesheet notes, and time entry notes
  • Retrieve time periods
  • Create, update, or retrieve project status reports
  • Create or update integration instances 
  • Retrieve values from lookups

 

Authorize and Authenticate for the APIs

To authorize to use the REST APIs, verify that you have the API - Access right assigned. In addition, verify that you have the appropriate application rights to view or update the specific functional areas in the product. For example, a specific user has the API - Access right but does not have the project create access right. When this user makes a POST request for projects, the user gets a "401 unauthorized" error message.

The REST APIs support the following methods for authenticating user requests:

  • Basic Authentication that is based on an encoded username and password
  • Session or cookie based

 

Tools: For developing code surrounded by restful web services, you need to test your method, payoad and its possible response. For consuming restful web services there are number of tools available like: Insomnia Rest Client, Paw, HTTpie.

I'm using Postman and did some basic project fetch and update.

 

Get data for all project from CA PPM

 

  • Adding New Custom Attribute

    Out-of-the-box, only some of the project and task attributes are currently enabled for the APIs. In addition, you can enable custom attributes of specific data types for projects and tasks for the APIs. To enable these custom project and task attributes for the APIs, specify their API Attribute ID values as described in the following procedure.

    Follow these steps:

    1. Open Administration, and from Studio, click Objects.
    2. Select the object (project or task).
    3. Click Attributes.
    4. Select the attribute that you want to enable for the APIs.
    5. Enter a value in the API Attribute ID field.
    6. Verify that the ID value meets the following requirements:
      • Contains lowercase or uppercase letters or numeric digits only 
      • Is unique for an object 
        To uniquely identify your custom attributes, we recommend that you prefix your API Attribute IDs with specific letters (for example, with your organization name). Making your API Attribute IDs unique prevents conflicts during a future upgrade when new attributes are introduced. For example, an organization such as ACME Corporation can assign the following unique API Attribute ID to their Compliance attribute: "acmeCompliance". We also recommend that you use Camel Case notation to name your custom attributes.
    7. Click Save and Return.

    The API Attribute ID is the reference key for an attribute that appears in the result set of an API call.

    The following custom attribute data types are not supported for the REST APIs:

    • Large String
    • Money
    • Multi Valued Lookup
    • Attachment
    • Time Varying

    The interactive REST API reference documentation allows you to query the attributes that the REST APIs support, You can also query your custom attributes.

  • Project Read and Write 

         1) All Project Read

                     URL /projects

                     Method GET

                     Response Document Type application/json 

        2) One Project Read 

                      URL /projects/{project_internal_id}

                      Method GET

                      Response Document Type application/json 

        3) Updating Project Name 

                        URL /projects/{project_internal_id}

                        Method PATCH

                        Response Document Type application/json 

                        Request Document Type application/json 

                        Request Payload  {  "name": "ProjectNameChange" }

         4) Creating New Project

                        URL /projects

                        Method POST

                        Response Document Type application/json 

                        Request Document Type application/json 

                        Request Payload  {  "code": "P0000001",  "name": "ProjectNameChange" }

         5) Creating Multiple new Projects

                        URL /projects

                        Method POST

                        Response Document Type application/json 

                        Request Document Type application/json 

                        Request Payload {

                                                             "d": ["code": "PRJ001", "name": "PPM Project 1"}, 

                                                                   {"code": "PRJ002", "name": PPM Project 2"}]

                                                          }

  • Timesheet adjustment

                        URL /timesheets

                        Method POST

                        Response Document Type application/json 

                        Request Document Type application/json 

                        Request Payload { "adjustedTimesheetId": 5000000 }

Note: you need to pass timesheet id need to be adjusted 

 

  • Filter Expressions & Some Query Parameters

 

offsetprojects?offset=100
limitprojects?limit=50
sortprojects?sort=code desc

 

projects?sort=name,code desc
fieldsprojects?fields=name,isActive
filterprojects?filter=(isActive = true)
linksprojects?links=true
expandprojects?expand=(tasks=(fields=(code,startDate,costType)),teams)
OperatorTitleExample
=Equal(name = 'project1')
!=Not Equal(isActive != false)
>Greater Than(scheduleStart > '2015-08-18T11:00:00')
>=Greater Than or Equal To(scheduleStart >= '2015-07-15T08:00:00')
<Less Than(scheduleFinish < '2015-11-18T19:00:00')
<=Less Than or Equal To(scheduleFinish <= '2015-12-31T19:00:00')
startsWithString Starts With(name startsWith 'abc')
endsWithString Ends With(name endsWith 'xyx')
andLogical AND((name = 'project1') and (isActive = true))
orLogical OR((name startsWith 'proj') or (isApproved = true))

 

Example 

1) Get Project start with Name T 

                    URL /projects?filter=(name startsWith'T')

                     Method GET

                     Response Document Type application/json 

2) Increasing Project list limit

                     URL /projects?limit=75

                     Method GET

                     Response Document Type application/json 

 

You can further use https://<hostname>:<port>/<context>/rest/describe/index.html#/ URL for API Documentation and reference provided by CA.The API documentation contains all the sample requests for each endpoint.

 

cappm ca ppm rest ca ppm*

We have already achieved Rendering HTML inside CA PPM via Lookup, if you have not viewed my previous blog on html lookup then i will recommend you to first go through HTML Fancy Lookups: Getting Started

 

There are few clients where they want to view different sub-object data inside their master object and they want to create new instance or navigate into that instance for updating data from single view. 

 

For example, A client wants to view Top 5 Status Report with its Top Risk, Issue & Change with Projects Overall Status Indicators with task timeline along with Financial Data with some interactive Jasper reports to run from dashbaord type view. I have created a similar layout for Project as shown below: 

 

               <---------------------------------- Screenshot go here ----------------------------------->

Screen #1

           

 

Now how to achieve inline list inside Master Object sub-pages, lets start with our first inline list.

1) Create a Html file and javascript file, which is going to bring your dynamic id and other parameters from url, and place them in Knowledge Store. From Html you need to call JSP which is placed in CA PPM server inside custom folder. JSP page is going to query from CA PPM Database for dynamic inline table. 

2) Create a Dynamic Lookup with html page link from Knowledge store as Html_dsiplay.
3) Create an attribute in custom Object with this Lookup
4) Set Lookups Default Value
5) Set Lookup to Read Only
6) Set "Populate default where null", in case you have already created instance before this attribute creation.
7) Place this Attribute in Create, Edit, filter layout (Note: it won't work in List).
8) From Fields set this Attribute to Pull-Down instead of Browse.

 

Please provide your feedback/comment/concerns over html lookup for health discussion.

 

html lookups cappm ppm lookupslookup

CA PPM Lookups are powerful and widely used while achieving customization from getting dynamic values based on user login to parameter mapping or cascaded value into different lookup etc. Today we are going to learn how to leverage Lookups power to render Html into CA PPM pages to achieve some fancy stuffs.

 

Before we go into code, here are some examples of fancy html lookups.

 

               <------------------------------------- Screenshots go here ---------------------------------->

 

Screen#1 Video saved in Knowledge Store and embedding Youtube Video - used in organizations for communication  and trainings purpose and help videos for Project / Approval Process.

 

 

Screen#2 Images linked to JasperReport - For running jasper report inside instance,

example: running Project Status Report from Project general page.

 

sample backend URL: /reportservice/flow.html?_flowId=viewReportFlow&reportUnit=/shared/reports/ProfileReport&standAlone=true&decorate=no&ParentFolderUri=/shared/reports&ResourceId=5001005&output=pdf

Jasper report Output:

 

 

Screen#3 Interactive web page with Canvas and input control - For creative UI and input controls for changing view.

               

 

Possible benefit in CA PPM:

1) More flexible view with better user experience

2) Interactive data input based on dynamic parameters passed to html.

3) Knowledge Store for saving html and javascript for easy administration.

 

How can we achieve Html inside lookup?

 

For any CA PPM Lookup to render html inside page via lookup you need to set following lookup properties.

 

1) Create a Dynamic Lookup with some html data to display.
      For example:
               <------------------------------------- Code goes here ------------------------------------------->
                     SELECT
                             @select:1:id@
                            ,@select:html_display:html_display@
                     FROM
                           (SELECT
                                 '<!DOCTYPE html>
                                          <html>
                                             <body>
                                                  <div id="page">
                                                  <div id="logo">
                                                <h1><a href="/" id="logoLink">My First Website</a></h1>
                                                   </div>
                                                <div id="nav">
                                                <ul>
                                                <li><a href="#/home.html">Home</a></li>
                                                <li><a href="#/about.html">About</a></li>
                                                <li><a href="#/contact.html">Contact</a></li>
                                                </ul>
                                             </div>
                                       <div id="content">
                                       <h2>Home</h2>
                                           <p>
                                               This is my first webpage! I was able to code all the HTML and CSS in order to make it. Watch out world of web design here I come!
                                          </p>
                                          <p>
                                                   I can use my skills here to create websites for my business, my friends and family, my C.V, blog or articles. As well as any games or more experiment stuff (which is what the web is really all about).
                                          </p>
                                         </div>
                                 <div id="footer">
                                       <p>Webpage made by <a href="/" target="_blank">[your name]</a> </p>
                                 </div>
                                 </div>
                              </body>
                              </html>' as html_display
                           FROM DUAL) Html_sql
               <------------------------------------- Code Ends ----------------------------------------->


2) Create an attribute in custom Object with this Lookup
3) Set Lookup Default Value
4) Set Lookup to Read Only
5) Set "Populate default where null", in case you have already created instance before this attribute creation.
6) Place this Attribute in Create, Edit, filter layout (Note: It does not work in List).
7) Set this Attribute to Pull-Down instead of Browse from Fields 

Let's Check how our First Html Lookup looks like:
               <---------------------------------- Screenshots go here ---------------------------------->

Screen#1 Filter Layout
                  

 

Screen#2 Create Layout

 

Screen#3 Edit Layout


                

However, Lookup has some limitations. We can not put large sql inside dynamic lookup as it has restrictions. So, this leads to use of knowledge store to save web documents and images, which we can call in our query to achieve better dynamic approach and easy administration.

Let's achieve some HTML rendering via Knowledge Store.

Please find attached Timeline.html file as an attachment, this file need to be placed in KS and link needs to be modified in code as highlighted in bold.

 

1) Create a Dynamic Lookup with some html data to display.
For example:
               <--------------------------------- Code goes here --------------------------------------------->

        SELECT
           @select:1:id@
          ,@select:Html_display:Html_display@
       FROM
       ( SELECT
         ' <iframe
         src = "../niku/app?action=dms.viewFile&RhXm0r7tSeUqEr=true&fileId=5000039&fileName=Timeline.html"
                  width = "400%"
                   height = "300"
                   scrolling = "yes" />' as Html_display

         FROM DUAL ) Html_SQL


               <--------------------------------- Code Ends ---------------------------------------------->
2) Create an attribute in custom Object with this Lookup.
3) Set Lookup Default Value.
4) Set Lookup to Read Only.
5) Set "Populate default where null", in case you have already created instance before this attribute creation.
6) Place this Attribute in Create, Edit, filter layout (Note: It does not work in List).
7) Set this Attribute to Pull-Down instead of Browse from Fields.

Lets Check how our First Html Lookup collaborated with Knowledge Store is looking Now.
               <------------------------------------ Screenshots go here ---------------------------------->

             

By using these fancy lookups, you can also achieve Project Task interactive Timelining, Status Indicator over Project, Inline of Sub Object inside Master Object, Navigation with Status Indicator. Also, lot of other stuff  can be achieved as your creative thinking goes.

 

 

Upcoming Post:

Next Blog will be on Inline view of sub-object inside Master Object with Project Phase indicator and task timeline, stay connected