[Workaround] Filter on location/release in embedded filters and have multi-level embedded filters

Options
Jan Kastning
Jan Kastning Member Posts: 32
edited October 2022 in

Hi all,

I am not sure if someone already posted this, but I though sharing this might help some of you:

Although the Jama GUI is not capable of using the location or release field in embedded filters or embedding filters over multiple levels, the rest of Jama seems to be capable of doing so.

If you create a new filter and click on "View in list" Jama will use the search query in the site address / URL. This query can be altered to filter on location/release on embedded filters and also embed filters over multiple levels.

See the following example where all "A"-items are linked togeter and also all "B"-items (CR A -> CUS A -> ... -> SWUD A -> SWUT A) over 8 layers total:
image
Basically, I altered the search query to filter for:
CR with location under <project root node> and which has downlink to CUS which has downlink to SYRA which ... has downlink to SWUD which has downlinkt to SWUT which is in Folder A.
image

This also works for releases in embedded filter. When changing the query to "... has downlink to SWUT which is in Folder A or is in release XYZ" and "CR B" being release "XYZ", both items are shown:
image
Because I don't think doing this manually is a good idea, please see the following python script I wrote (See this site if you do not have python installed). You just have to fill in the BaseLink (top most filter search query = URL in your browser when you hit "View in List" on a new filter) and the list of replacments (replacing from top to bottom). For each embedded query you have to do the same process as for the base link (you can use the full URL). For location/release embedding: The API ID of an item can be found in the URL when clicking on an item:
image
Your unique replacement text (e.g., JAMA_REPLACE_MEx) must be in a name field with "contains word"-logic:

image
The script will output the link for your search query.
Please have mercy regarding my coding style.. I am not a software engineer ;)

#Create the filter search query and for any field you want to be replaced use the field "Name" + "contains word" + a unique word (e.g. "JAMA_REPLACE_MEx").

#Top most search query
BaseLink = "QUERY LINK HERE"

#Put any replacement here, columns:
#1: Type of replacement ("Embed", "Release" or "Location")
#2: Text to know which field to replace
#3: API ID of parent item for "Location" or "Release" | Full link including search query for "Embed"
Replacements = [
                ["Embed","JAMA_REPLACE_ME1","QUERY LINK HERE"]
                ,["Embed","JAMA_REPLACE_ME2","QUERY LINK HERE"]
                ,["Embed","JAMA_REPLACE_ME3","QUERY LINK HERE"]
                ,["Embed","JAMA_REPLACE_ME4","QUERY LINK HERE"]
                ,["Embed","JAMA_REPLACE_ME5","QUERY LINK HERE"]
                ,["Embed","JAMA_REPLACE_ME6","QUERY LINK HERE"]
                ,["Location","JAMA_REPLACE_ME7","API ID HERE"]
                ,["Release","JAMA_REPLACE_ME8","API ID HERE"]
               ]

#Jama properties for location/release field, might be different on your Jama installation
LocationField_Id = "2005"
LocationField_DataType = "1007"
LocationField_Type = "3"
ReleaseField_Id = "260"
ReleaseField_DataType = "7"
ReleaseField_Type = "1"

#The variable OutputLink is altered according to the Replacements list above in the given order:
OutputLink = BaseLink
for row in Replacements:
    if row[0] == "Location":
        #Find position of value to be replaced in link text
        ReplacementIndex_Value_Start = OutputLink.find(row[1])
        #Find respective search field
        ReplacementIndex_Field_Start = OutputLink.rfind("%22field%22%3A%7B%22id%22",0,ReplacementIndex_Value_Start) + 17   #Search for     "field":{"id"
        ReplacementIndex_Field_End = OutputLink.rfind("%7D%2C%22operator%22%3A",0,ReplacementIndex_Value_Start) + 0        #Search for     },"operator":
        #Build replacement field (location)
        LocationFieldReplacementText = "%22id%22%3A"+LocationField_Id+"%2C"
        LocationFieldReplacementText += "%22name%22%3A%22parent%22%2C"
        LocationFieldReplacementText += "%22display%22%3A%22Location%22%2C"
        LocationFieldReplacementText += "%22fieldDataType%22%3A"+LocationField_DataType+"%2C"
        LocationFieldReplacementText += "%22type%22%3A"+LocationField_Type
        #Find CONTAINS_WORD operator and replace with IS_UNDER operator
        StartIndex_CONTAINSWORD = OutputLink.find("CONTAINS_WORD",ReplacementIndex_Field_End)
        EndIndex_CONTAINSWORD = StartIndex_CONTAINSWORD + 13                                                                #13 = Lenght of CONTAINS_WORD
        OutputLink = OutputLink[:StartIndex_CONTAINSWORD] + "IS_UNDER" + OutputLink[EndIndex_CONTAINSWORD:]  
        #Rebuild search query by 
        OutputLink = OutputLink[:ReplacementIndex_Field_Start] + LocationFieldReplacementText + OutputLink[ReplacementIndex_Field_End:]
        
        #Replace first occurence JAMA_REPLACE_MEx with parent item ID
        OutputLink = OutputLink.replace(row[1],row[2],1)

    elif row[0] == "Release":
        #Find position of value to be replaced in link text
        ReplacementIndex_Value_Start = OutputLink.find(row[1])
        #Find respective search field
        ReplacementIndex_Field_Start = OutputLink.rfind("%22field%22%3A%7B%22id%22",0,ReplacementIndex_Value_Start) + 17   #Search for     "field":{"id"
        ReplacementIndex_Field_End = OutputLink.rfind("%7D%2C%22operator%22%3A",0,ReplacementIndex_Value_Start) + 0        #Search for     },"operator":
        #Build replacement field (location)
        ReleaseFieldReplacementText = "%22id%22%3A"+ReleaseField_Id+"%2C"
        ReleaseFieldReplacementText += "%22name%22%3A%22release%22%2C"
        ReleaseFieldReplacementText += "%22display%22%3A%22Release%22%2C"
        ReleaseFieldReplacementText += "%22fieldDataType%22%3A"+ReleaseField_DataType+"%2C"
        ReleaseFieldReplacementText += "%22type%22%3A"+ReleaseField_Type
        #Find CONTAINS_WORD operator and replace with IS_UNDER operator
        StartIndex_CONTAINSWORD = OutputLink.find("CONTAINS_WORD",ReplacementIndex_Field_End)
        EndIndex_CONTAINSWORD = StartIndex_CONTAINSWORD + 13                                                                #13 = Lenght of CONTAINS_WORD
        OutputLink = OutputLink[:StartIndex_CONTAINSWORD] + "EQUALS" + OutputLink[EndIndex_CONTAINSWORD:]  
        #Rebuild search query by 
        OutputLink = OutputLink[:ReplacementIndex_Field_Start] + ReleaseFieldReplacementText + OutputLink[ReplacementIndex_Field_End:]
        
        #Replace first occurence JAMA_REPLACE_MEx with release item ID
        OutputLink = OutputLink.replace(row[1],row[2],1)

    elif row[0] == "Embed":
        #Find position of value to be replaced in link text
        ReplacementIndex_Value_Start = OutputLink.find(row[1])
        #Find start of respective search field
        ReplacementIndex_Field_Start = OutputLink.rfind("%5B%7B%22parentId%22%3A",0,ReplacementIndex_Value_Start) + 6       #Search for     [{"parentId":
        #Find end of respective search field (closing curly bracket)
        curindex = OutputLink.find("%7B",ReplacementIndex_Field_Start-3)
        opencounter = 1
        while opencounter > 0:
            index_nextopen = OutputLink.find("%7B",curindex+3)
            index_nextclose = OutputLink.find("%7D",curindex+3)
            if index_nextopen < index_nextclose:
                curindex = index_nextopen
                opencounter += 1
            else:
                curindex = index_nextclose
                opencounter -= 1
        ReplacementIndex_Field_End = curindex
        #Extract replacement query from given filter link
        EmbedFilterLink = row[2]
        ReplacerIndex_Field_Start = EmbedFilterLink.find("%22parentId%22%3A2",0)    #Search for "parentID":2
        #Find end of block (closing curly bracket)
        curindex = EmbedFilterLink.find("%7B",ReplacerIndex_Field_Start-3)
        opencounter = 1
        while opencounter > 0:
            index_nextopen = EmbedFilterLink.find("%7B",curindex+3)
            index_nextclose = EmbedFilterLink.find("%7D",curindex+3)
            if index_nextopen < index_nextclose:
                curindex = index_nextopen
                opencounter += 1
            else:
                curindex = index_nextclose
                opencounter -= 1
        ReplacerIndex_Field_End = curindex        
        
        OutputLink = OutputLink[:ReplacementIndex_Field_Start] + EmbedFilterLink[ReplacerIndex_Field_Start:ReplacerIndex_Field_End] + OutputLink[ReplacementIndex_Field_End:]

    else:
        #Ignore row
        pass

print(OutputLink)
Please note:
  • You should filter on location (e.g., project root node) at least on the top level filter otherwise Jama will give you all results over all projects in your Jama instance.
  • In the script you can only check for "is under" or "is in release" for now, but checking for e.g., "is not under" is not that complicated. I will try to add this until end of this week.
  • I did not care about the id and parent id attribute in the filter query. Fortunately, it works in our Jama (Jama Connect 8.74.1; self hosted). If you have any troubles with this working in your Jama, maybe check the id's first.
  • In theory the other attributes of a filter should not be impacted by the script, but I didn't run any tests on more complex filters. Please feel free to share your expierence with the script.
  • You can still edit the top level filter but if you try to edit the embedded filter you will receive the following prompt
    image
  • The best part: You can actually save the filter with the altered embedded filters! It seems it's just the Jama GUI not being able to handle this process. Just open the filter link, click on "View to edit" and save the filter.
Hope this helps some of you, any feedback is welcome!

BR,
Jan

------------------------------
Jan Kastning
System Engineer
Panasonic Industrial Devices Europe GmbH
------------------------------