Skip to content

Commit

Permalink
Added: Project plugin retrieve jsgantt module via npm (OFBIZ-12804)
Browse files Browse the repository at this point in the history
An outdated version of jsgantt was previously included in
ofbiz-framework sources as part of common-theme. These sources have been
removed from common-theme and the project plugin will now retrieve an
updated version of jsgantt, jsgantt-improved, from NPM.

The newer version of jsgantt is not completely compatible with the
previous version used by OFBiz, so some changes in how the gantt chart
was initialised were necessary.

Common code has been extracted to static javascript file. Data
representing gantt chart items is rendered to a hidden field on screen
where it is retrieved by client-side code and used to construct the
gantt chart.
  • Loading branch information
danwatford authored Apr 18, 2023
1 parent 145da81 commit ea24c8f
Show file tree
Hide file tree
Showing 11 changed files with 2,086 additions and 67 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
bin/
bin/
node_modules/
1 change: 1 addition & 0 deletions projectmgr/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.gradle
26 changes: 26 additions & 0 deletions projectmgr/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

plugins {
id 'ofbiz-node-conventions'
}

node {
nodeProjectDir = file("webapp/projectmgr")
}
72 changes: 58 additions & 14 deletions projectmgr/groovyScripts/GanttChart.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@
*/


import groovy.json.JsonOutput
import org.apache.ofbiz.base.util.UtilDateTime
import org.apache.ofbiz.base.util.UtilValidate
import org.apache.ofbiz.entity.condition.EntityCondition
import org.apache.ofbiz.entity.condition.EntityOperator

import java.sql.Timestamp

projectId = parameters.projectId
userLogin = parameters.userLogin

//project info
result = runService('getProject', [projectId : projectId, userLogin : userLogin])
result = runService('getProject', [projectId: projectId, userLogin: userLogin])
project = result.projectInfo
if (project && project.startDate)
context.chartStart = project.startDate
Expand All @@ -41,7 +43,9 @@ else
if (project == null) return

ganttList = new LinkedList()
result = runService('getProjectPhaseList', [userLogin : userLogin , projectId : projectId])
List<Map<String, Object>> ganttItems = []

result = runService('getProjectPhaseList', [userLogin: userLogin, projectId: projectId])
phases = result.phaseList
if (phases) {
phases.each { phase ->
Expand All @@ -61,15 +65,34 @@ if (phases) {
}
newPhase.workEffortTypeId = "PHASE"
ganttList.add(newPhase)

ganttItems << [
pID : phase.phaseId as Integer,
pName : phase.phaseSeqNum ? "${phase.phaseSeqNum}. ${phase.phaseName}" : phase.phaseName,
pStart : '',
pEnd : '',
pPlanStart: '',
pPlanEnd : '',
pClass : 'ggroupblack',
pLink : '',
pMile : 0,
pRes : '',
pComp : 0,
pGroup : 1,
pParent : 0,
pOpen : 1,
pDepend : ''
]

cond = EntityCondition.makeCondition(
[
EntityCondition.makeCondition("currentStatusId", EntityOperator.NOT_EQUAL, "PTS_CANCELLED"),
EntityCondition.makeCondition("workEffortParentId", EntityOperator.EQUALS, phase.phaseId)
EntityCondition.makeCondition("currentStatusId", EntityOperator.NOT_EQUAL, "PTS_CANCELLED"),
EntityCondition.makeCondition("workEffortParentId", EntityOperator.EQUALS, phase.phaseId)
], EntityOperator.AND)
tasks = from("WorkEffort").where(cond).orderBy("sequenceNum","workEffortName").queryList()
tasks = from("WorkEffort").where(cond).orderBy("sequenceNum", "workEffortName").queryList()
if (tasks) {
tasks.each { task ->
resultTaskInfo = runService('getProjectTask', [userLogin : userLogin , taskId : task.workEffortId])
resultTaskInfo = runService('getProjectTask', [userLogin: userLogin, taskId: task.workEffortId])
taskInfo = resultTaskInfo.taskInfo
taskInfo.taskNr = task.workEffortId
taskInfo.phaseNr = phase.phaseId
Expand Down Expand Up @@ -100,13 +123,12 @@ if (phases) {
if (!taskInfo.estimatedCompletionDate && !duration) {
taskInfo.estimatedCompletionDate = UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate, 3)
} else if (!taskInfo.estimatedCompletionDate && duration) {
taskInfo.estimatedCompletionDate = UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate, duration/8)
taskInfo.estimatedCompletionDate = UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate, duration / 8)
}
taskInfo.estimatedStartDate = UtilDateTime.toDateString(taskInfo.estimatedStartDate, "MM/dd/yyyy")
taskInfo.estimatedCompletionDate = UtilDateTime.toDateString(taskInfo.estimatedCompletionDate, "MM/dd/yyyy")

taskInfo.workEffortTypeId = task.workEffortTypeId
if (security.hasEntityPermission("PROJECTMGR", "_READ", session) || security.hasEntityPermission("PROJECTMGR", "_ADMIN", session)) {
taskInfo.url = "/projectmgr/control/taskView?workEffortId="+task.workEffortId
taskInfo.url = "/projectmgr/control/taskView?workEffortId=" + task.workEffortId
} else {
taskInfo.url = ""
}
Expand All @@ -123,18 +145,40 @@ if (phases) {
taskInfo.preDecessor = ""
for (i in latestTaskIds) {
if (count > 0) {
taskInfo.preDecessor = taskInfo.preDecessor +", " + i
taskInfo.preDecessor = taskInfo.preDecessor + ", " + i
} else {
taskInfo.preDecessor = taskInfo.preDecessor + i
}
count ++
count++
}
}

ganttItems << [
pID : taskInfo.taskNr as Integer,
pName : taskInfo.taskSeqNum ? "${taskInfo.taskSeqNum}. ${taskInfo.taskName}" : taskInfo.taskName,
pStart : taskInfo.estimatedStartDate.toLocalDateTime().getDateString(),
pEnd : (taskInfo.estimatedCompletionDate as Timestamp).toLocalDateTime().getDateString(),
pPlanStart: (taskInfo.estimatedStartDate as Timestamp).toLocalDateTime().getDateString(),
pPlanEnd : (taskInfo.estimatedCompletionDate as Timestamp).toLocalDateTime().getDateString(),
pClass : taskInfo.workEffortTypeId == 'MILESTONE' ? 'gmilestone' : 'gtaskgreen',
pLink : taskInfo.url,
pMile : taskInfo.workEffortTypeId == 'MILESTONE' ? 1 : 0,
pRes : taskInfo.resource,
pComp : taskInfo.completion,
pGroup : 0,
pParent : taskInfo.phaseNr,
pOpen : taskInfo.workEffortTypeId == 'MILESTONE' ? 0 : 1,
pDepend : taskInfo.preDecessor ?: ''
]

taskInfo.estimatedStartDate = UtilDateTime.toDateString(taskInfo.estimatedStartDate, "MM/dd/yyyy")
taskInfo.estimatedCompletionDate = UtilDateTime.toDateString(taskInfo.estimatedCompletionDate, "MM/dd/yyyy")

ganttList.add(taskInfo)
}
}
}
}

context.phaseTaskList = ganttList

context.phaseTaskListJson = JsonOutput.toJson(ganttItems)
44 changes: 3 additions & 41 deletions projectmgr/template/project/GanttChart.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -19,46 +19,8 @@ under the License.
-->

<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
<script type="application/javascript">
var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'day');

g.setShowRes(1); // Show/Hide Responsible (0/1)
g.setShowDur(1); // Show/Hide Duration (0/1)
g.setShowComp(1); // Show/Hide % Complete(0/1)
// Parameters (pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen)
<#list phaseTaskList as t>
<#if "PHASE" == t.workEffortTypeId>
g.AddTaskItem(new JSGantt.TaskItem("${t.phaseNr}", "${t.phaseSeqNum!}. ${t.phaseName}", "", "", "00ff00", "", 0, "", 0, 1, 0, 1));
</#if>
<#if "TASK" == t.workEffortTypeId>
g.AddTaskItem(new JSGantt.TaskItem("${t.taskNr}","${t.taskSeqNum!}. ${t.taskName}","${StringUtil.wrapString(t.estimatedStartDate)}", "${StringUtil.wrapString(t.estimatedCompletionDate)}","009900", "${t.url}", 0 , "${t.resource!}", ${t.completion!} , 0, ${t.phaseNr}, 1<#if t.preDecessor??>, "${t.preDecessor}"</#if>));
</#if>
<#if "MILESTONE" == t.workEffortTypeId>
g.AddTaskItem(new JSGantt.TaskItem("${t.taskNr}","${t.taskName}","${StringUtil.wrapString(t.estimatedStartDate)}", "${StringUtil.wrapString(t.estimatedCompletionDate)}","00ff00", "", 1 , "${t.resource!}", ${t.completion!} , 0,${t.phaseNr}, "", "" ));
</#if>
</#list>
<#--
TaskItem(pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend)
pID: (required) is a unique ID used to identify each row for parent functions and for setting dom id for hiding/showing
pName: (required) is the task Label
pStart: (required) the task start date, can enter empty date ('') for groups
pEnd: (required) the task end date, can enter empty date ('') for groups
pColor: (required) the html color for this task; e.g. '00ff00'
pLink: (optional) any http link navigated to when task bar is clicked.
pMile:(optional) represent a milestone
pRes: (optional) resource name
pComp: (required) completion percent
pGroup: (optional) indicates whether this is a group(parent) - 0=NOT Parent; 1=IS Parent
pParent: (required) identifies a parent pID, this causes this task to be a child of identified task
pOpen: UNUSED - in future can be initially set to close folder when chart is first drawn
pDepend: dependency: need previous task finished.
-->
g.Draw();
g.DrawDependencies();
</script>
<input id="ofbizGantItemsJson" type="hidden" value="${phaseTaskListJson}"/>

<script type="application/javascript" src="/projectmgr/node_modules/jsgantt-improved/dist/jsgantt.js"></script>
<script type="application/javascript" src="/projectmgr/static/projectmgr.js"></script>
2 changes: 1 addition & 1 deletion projectmgr/webapp/projectmgr/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<filter-class>org.apache.ofbiz.webapp.control.ControlFilter</filter-class>
<init-param>
<param-name>allowedPaths</param-name>
<param-value>/error:/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images:/static:/js</param-value>
<param-value>/error:/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images:/static:/js:/node_modules/jsgantt-improved</param-value>
</init-param>
<init-param>
<param-name>redirectPath</param-name>
Expand Down
Loading

0 comments on commit ea24c8f

Please sign in to comment.