Sometimes in our apps we want to store hierarchical structures. In our case let's call them areas. In our case there will be one root area and infinite number of child areas with limited number of levels. In the dataset every area will store refrence to its parent area except the root one.

Using custom view and some JS magic we can the show the hierarchy like this:

The actual source code of this view is not really important and most likely will differ case to case. 

Functions

Let's explain functions to work with hierarchy. We assume that our dataset is called "AREAS" and has at least 2 attributes "ID" and "PARENT_AREA" (translated to L_ID and L_PARENT_AREA codes).

Parents

In case we want list area and all it's parents we can use formula function listHierarchicalParentMembersForAttribute. In our case the usage is:

def allParentAreas = listHierarchicalParentMembersForAttribute('AREAS', isEqualFilter('L_ID', areaId), 'L_ID', 'L_PARENT_AREA')
def allParentAreasIds = allParentAreas.collect { it.value }

Now we have IDs of current area and all it's parents in allParentAreasIds variable. We can use it to get records from another dataset for example:

def userRows = readDataset('USERS_AREA',-1,isInFilter('L_AREA_ID', allParentAreasIds as String[]), null)

Children

We can do the same with children as with parents. Difference is that now we get all child areas:

def allChildAreas = listHierarchicalChildMembersForAttribute('AREAS', isInFilter('L_ID', adminAreaIds as String[]), 'L_ID', 'L_PARENT_AREA')
def allChildAreasIds = allChildAreas.collect { it.value }


Areas hierarchy extension

Here's the custom view shown above:

Areas hierarchy.zip

And this is its formula config:

//importFromExt(User group management,AreaFunctions)

def w = currentDomain()
def userId = getCurrentUser().id

def adminOfAreasId = []
def adminOf = readDataset('USERS_AREA', -1, andFilter(isEqualFilter('L_USER_ID',userId as String), isEqualFilter('M_ADMIN', 1)), null)
if (adminOf.size() > 0) {
  def adminOfAreas = adminOf.collect { it.getValues()['L_AREA_ID'] }
  def allAreas = listHierarchicalChildMembersForAttribute('AREAS', isInFilter('L_ID', adminOfAreas as String[]), 'L_ID', 'L_PARENT_AREA')
  adminOfAreasId = allAreas.collect { it.value }
}
def userOfAreasId = []
def userOf = readDataset('USERS_AREA', -1, andFilter(isEqualFilter('L_USER_ID',userId as String), isEqualFilter('M_USER', 1)), null)
if (userOf.size() > 0) {
  def userOfAreas = userOf.collect { it.getValues()['L_AREA_ID'] }
  def allAreas = listHierarchicalChildMembersForAttribute('AREAS', isInFilter('L_ID', userOfAreas as String[]), 'L_ID', 'L_PARENT_AREA')
  userOfAreasId = allAreas.collect { it.value }
}

def ww = readDataset('SYSTEM.COMPANIES', 1, isEqualFilter('L_SCHEMA', w.schemaName), null)
def company = [:]
company << ww[0].values
company.siteCount = countDataset('CONSTRUCTION_SITES', null)

def d = readDataset('AREAS',-1,null,null)
def areas = []
d.each { area -> 
  def v = [:]
  v << area.values
  v.siteCount = countDataset('CONSTRUCTION_SITES', isEqualFilter('L_AREA', v.L_ID))
  areas << v
}
def s = readDataset('CONSTRUCTION_SITES',-1,null,null)
def sites = []
s.each {
  sites << it.values
}
sites = sites.groupBy { it['L_AREA'] }
def conf = [areas:areas, company:company, sitesByArea:sites]
def groups = listUsersGroupsInDomain()
conf.isAdmin = AreaFunctions.isCompanyAdmin()
if (conf.isAdmin || adminOfAreasId.size() > 0) {
conf.addUrl = "/bi/report/detail.report.layout.rvd.actionbutton:openpopup/4oKi0kz5B7?t:ac=76&vr=76-22lVk46y9a"
conf.adminOfAreas = adminOfAreasId  
}
conf.isCompanyUser = groups.contains('Company users')

conf.userOfAreasId = userOfAreasId
conf.areaDetailUrl = '/bi/reports/areadetail?areaId='

conf.columnName = translate(['':'Name','ja':'名前'])
conf.columnParentArea = translate(['':'Parent area','ja':'親エリア'])
conf.columnSites = translate(['':'Sites','ja':'建設現場'])
conf.buttonSearch = translate(['':'Search','ja':'検索'])
conf.buttonShowAsHierarchy = translate(['':'Show as hierarchy','ja':'階層を表示'])
conf.buttonShowDetails = translate(['':'Show details','ja':'詳細を表示'])
conf.buttonShowAsList = translate(['':'Show as list','ja':'リスト表示'])
conf.detailsSiteLimit = translate(['':'Site limit','ja':'サイト制限'])
conf.detailsAllocatedSites = translate(['':'Allocated sites:','ja':'割り当てられたサイト'])
conf.buttonHideDetails = translate(['':'Hide details:','ja':'詳細を非表示'])
conf.unlimited = translate(['':'Unlimited','ja':'制限なし'])
conf.companyLabel = translate(['':'Company','ja':'会社'])
conf.levelLabel = translate(['':'Level','ja':'レベル'])

return conf

General concept is that users can open details only of certain areas based on USER_AREAS dataset value where users can be assigned as Area admins or Area users.

Explanation of some interesting lines in the code:

#7 - Fetch areas where user is set as admin

#10 - Get all child areas for these areas as user is admin in child areas too

#14 - Do the same as user

#21 - Read company record which represents current domain, it will be displayed when there is no area

#24 - Count number of sites in the company

#31 - Count sites for each area

#43 - When user is admin of at least one area, pass link to action button to add new area

#52 - Localization for all labels used in the custom view


  • No labels