You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jl...@apache.org on 2026/04/20 15:33:52 UTC
(ofbiz-plugins) branch release24.09 updated: Fixed: jsgantt-improved bloks qs.js update (OFBIZ-13339)
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-plugins.git
The following commit(s) were added to refs/heads/release24.09 by this push:
new 6055fad45 Fixed: jsgantt-improved bloks qs.js update (OFBIZ-13339)
6055fad45 is described below
commit 6055fad455a59c0360b28c228d6aa4a850e4367f
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Thu Apr 16 19:52:07 2026 +0200
Fixed: jsgantt-improved bloks qs.js update (OFBIZ-13339)
Reintegrates Gantt functionality into projectmgr application while updating
jsgantt-improved to its secure version 3.0.0.
This update fixes security issues.
---
projectmgr/README.md | 1 +
projectmgr/build.gradle | 26 +++
projectmgr/config/ProjectMgrUiLabels.xml | 24 +++
.../src/docs/asciidoc/_include/prjm_project.adoc | 1 +
.../org/apache/ofbiz/projectmgr/GanttChart.groovy | 177 +++++++++++++++++++++
projectmgr/template/project/GanttChart.ftl | 26 +++
.../webapp/projectmgr/WEB-INF/controller.xml | 6 +
projectmgr/webapp/projectmgr/WEB-INF/web.xml | 2 +-
projectmgr/webapp/projectmgr/package-lock.json | 38 +++++
projectmgr/webapp/projectmgr/package.json | 9 ++
projectmgr/webapp/projectmgr/static/projectmgr.css | 25 +++
projectmgr/webapp/projectmgr/static/projectmgr.js | 40 +++++
projectmgr/widget/CommonScreens.xml | 1 +
projectmgr/widget/ProjectMenus.xml | 8 +
projectmgr/widget/ProjectScreens.xml | 32 ++++
15 files changed, 415 insertions(+), 1 deletion(-)
diff --git a/projectmgr/README.md b/projectmgr/README.md
index 9ffa2dda5..dec6f01f3 100644
--- a/projectmgr/README.md
+++ b/projectmgr/README.md
@@ -13,6 +13,7 @@ The Project Management application enables organisations to manage their interna
Resource assignement to projects
Resource allocation to tasks
Approval of time spent on tasks
+ Gantt charts for projects, phases and tasks
Time registration with different rates
Generate invoice from a project
Project copy
diff --git a/projectmgr/build.gradle b/projectmgr/build.gradle
new file mode 100644
index 000000000..6e020480f
--- /dev/null
+++ b/projectmgr/build.gradle
@@ -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")
+}
diff --git a/projectmgr/config/ProjectMgrUiLabels.xml b/projectmgr/config/ProjectMgrUiLabels.xml
index b369123db..b07a11874 100644
--- a/projectmgr/config/ProjectMgrUiLabels.xml
+++ b/projectmgr/config/ProjectMgrUiLabels.xml
@@ -833,6 +833,18 @@
<value xml:lang="zh">项目账单</value>
<value xml:lang="zh-TW">專案帳單</value>
</property>
+ <property key="PageTitleProjectGanttChart">
+ <value xml:lang="de">Projekt Gantt Chart</value>
+ <value xml:lang="en">Project Gantt Chart</value>
+ <value xml:lang="fr">Graphe Gantt du projet</value>
+ <value xml:lang="it">Progetto grafico gantt</value>
+ <value xml:lang="ja">プロジェクトガントチャート</value>
+ <value xml:lang="nl">Gant chart</value>
+ <value xml:lang="th">แผนผังคุมการกำหนดโปรเจค</value>
+ <value xml:lang="vi">Biểu đồ CHUNG của dự án</value>
+ <value xml:lang="zh">项目甘特图</value>
+ <value xml:lang="zh-TW">專案甘特圖</value>
+ </property>
<property key="PageTitleProjectInformation">
<value xml:lang="de">Projektinformationen</value>
<value xml:lang="en">Project Information</value>
@@ -1494,6 +1506,18 @@
<value xml:lang="zh">周五</value>
<value xml:lang="zh-TW">週五</value>
</property>
+ <property key="ProjectMgrGanttChart">
+ <value xml:lang="de">Gantt Chart</value>
+ <value xml:lang="en">Gantt Chart</value>
+ <value xml:lang="fr">Diagramme de Gantt</value>
+ <value xml:lang="it">Grafico gantt</value>
+ <value xml:lang="ja">ガントチャート</value>
+ <value xml:lang="nl">GANT chart</value>
+ <value xml:lang="th">แผนผังคุมการกำหนดงาน</value>
+ <value xml:lang="vi">Biểu đồ CHUNG</value>
+ <value xml:lang="zh">甘特图</value>
+ <value xml:lang="zh-TW">甘特圖</value>
+ </property>
<property key="ProjectMgrListMailingList">
<value xml:lang="de">Liste Mailing-List auf</value>
<value xml:lang="en">List Mailing List</value>
diff --git a/projectmgr/src/docs/asciidoc/_include/prjm_project.adoc b/projectmgr/src/docs/asciidoc/_include/prjm_project.adoc
index 837b28d6c..b986246a7 100644
--- a/projectmgr/src/docs/asciidoc/_include/prjm_project.adoc
+++ b/projectmgr/src/docs/asciidoc/_include/prjm_project.adoc
@@ -23,6 +23,7 @@ It is also the starting point to navigate to the various sub screens related to
== Sub screens
Following sub screens are provided:
+* Gantt chart
* Mailing List
* Phases
* Tasks
diff --git a/projectmgr/src/main/groovy/org/apache/ofbiz/projectmgr/GanttChart.groovy b/projectmgr/src/main/groovy/org/apache/ofbiz/projectmgr/GanttChart.groovy
new file mode 100644
index 000000000..33e118717
--- /dev/null
+++ b/projectmgr/src/main/groovy/org/apache/ofbiz/projectmgr/GanttChart.groovy
@@ -0,0 +1,177 @@
+/*
+ * 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.
+*/
+package org.apache.ofbiz.projectmgr
+
+import groovy.json.JsonOutput
+import org.apache.ofbiz.base.util.UtilDateTime
+import org.apache.ofbiz.entity.GenericValue
+import org.apache.ofbiz.entity.condition.EntityCondition
+import org.apache.ofbiz.entity.condition.EntityConditionList
+import org.apache.ofbiz.entity.condition.EntityExpr
+import org.apache.ofbiz.entity.condition.EntityOperator
+
+import javax.servlet.http.HttpSession
+import java.math.RoundingMode
+import java.sql.Timestamp
+
+final String taskStatusCompleted = 'PTS_COMPLETED'
+final int defaultTaskDurationDays = 3
+final String milestoneWorkEffortTypeId = 'MILESTONE'
+final String permissionCheckEntity = 'PROJECTMGR'
+final BigDecimal hundredPercent = new BigDecimal(100)
+
+String projectId = parameters.projectId
+GenericValue userLogin = parameters.userLogin as GenericValue
+
+Map<String, Object> result = runService('getProject', [projectId: projectId, userLogin: userLogin])
+Map<String, Object> project = result.projectInfo as Map<String, Object>
+if (project == null) {
+ return
+}
+
+context.chartStart = project.startDate ?: UtilDateTime.nowTimestamp() // default today's date
+context.chartEnd = project.completionDate ?: UtilDateTime.addDaysToTimestamp(UtilDateTime.nowTimestamp(), 14)
+
+List ganttList = []
+List<Map<String, Object>> ganttItems = []
+
+result = runService('getProjectPhaseList', [userLogin: userLogin, projectId: projectId])
+List<Map<String, Object>> phases = result.phaseList as List<Map<String, Object>>
+if (phases) {
+ phases.each { phase ->
+ Map<String, Object> newPhase = phase
+ newPhase.phaseNr = phase.phaseId
+ if (!newPhase.estimatedStartDate && newPhase.actualStartDate) {
+ newPhase.estimatedStartDate = newPhase.actualStartDate
+ }
+ newPhase.estimatedStartDate = newPhase.estimatedStartDate ?: context.chartStart
+
+ if (!newPhase.estimatedCompletionDate && newPhase.actualCompletionDate) {
+ newPhase.estimatedCompletionDate = newPhase.actualCompletionDateDate
+ }
+ newPhase.estimatedCompletionDate = newPhase.estimatedCompletionDate
+ ?: UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate as Timestamp, defaultTaskDurationDays)
+
+ 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: '',
+ ]
+
+ EntityConditionList<EntityExpr> cond = EntityCondition.makeCondition([
+ EntityCondition.makeCondition('currentStatusId', EntityOperator.NOT_EQUAL, 'PTS_CANCELLED'),
+ EntityCondition.makeCondition('workEffortParentId', EntityOperator.EQUALS, phase.phaseId)
+ ], EntityOperator.AND)
+ List<GenericValue> tasks = from('WorkEffort').where(cond).orderBy('sequenceNum', 'workEffortName').queryList()
+
+ if (tasks) {
+ tasks.each { task ->
+ Map<String, Object> resultTaskInfo = runService('getProjectTask', [userLogin: userLogin, taskId: task.workEffortId])
+ Map<String, Object> taskInfo = resultTaskInfo.taskInfo as Map<String, Object>
+ taskInfo.taskNr = task.workEffortId
+ taskInfo.phaseNr = phase.phaseId
+
+ taskInfo.resource = ((taskInfo.plannedHours &&
+ taskStatusCompleted != taskInfo.currentStatusId &&
+ taskInfo.plannedHours > taskInfo.actualHours) ? taskInfo.plannedHours : taskInfo.actualHours) +
+ ' Hrs'
+
+ BigDecimal durationHours = resultTaskInfo.plannedHours as BigDecimal
+ if (taskStatusCompleted == taskInfo.currentStatusId) {
+ taskInfo.completion = hundredPercent
+ } else {
+ BigDecimal actualHours = taskInfo.actualHours as BigDecimal
+ BigDecimal plannedHours = taskInfo.plannedHours as BigDecimal
+ taskInfo.completion = (actualHours && plannedHours)
+ ? (actualHours * hundredPercent).divide(plannedHours, 0, RoundingMode.UP)
+ : 0
+ }
+ if (!taskInfo.estimatedStartDate && taskInfo.actualStartDate) {
+ taskInfo.estimatedStartDate = taskInfo.actualStartDate
+ }
+ taskInfo.estimatedStartDate = taskInfo.estimatedStartDate ?: newPhase.estimatedStartDate
+
+ if (!taskInfo.estimatedCompletionDate && taskInfo.actualCompletionDate) {
+ taskInfo.estimatedCompletionDate = taskInfo.actualCompletionDate
+ }
+ if (!taskInfo.estimatedCompletionDate && !durationHours) {
+ taskInfo.estimatedCompletionDate =
+ UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate as Timestamp,
+ defaultTaskDurationDays)
+ } else if (!taskInfo.estimatedCompletionDate && durationHours) {
+ taskInfo.estimatedCompletionDate =
+ UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate as Timestamp,
+ durationHours / 8)
+ }
+
+ taskInfo.workEffortTypeId = task.workEffortTypeId
+ if (security.hasEntityPermission(permissionCheckEntity, '_READ', session as HttpSession) ||
+ security.hasEntityPermission(permissionCheckEntity, '_ADMIN', session as HttpSession)) {
+ taskInfo.url = '/projectmgr/control/taskView?workEffortId=' + task.workEffortId
+ } else {
+ taskInfo.url = ''
+ }
+
+ List<GenericValue> preTaskAssociations = from('WorkEffortAssoc')
+ .where('workEffortIdTo', task.workEffortId)
+ .orderBy('workEffortIdFrom')
+ .queryList()
+
+ taskInfo.preDecessor = preTaskAssociations*.getRelatedOne('FromWorkEffort', false)
+ .collect { we -> we.workEffortId as String }
+ .join(',')
+
+ ganttItems << [
+ pID: taskInfo.taskNr as Integer,
+ pName: taskInfo.taskSeqNum ? "${taskInfo.taskSeqNum}. ${taskInfo.taskName}" : taskInfo.taskName,
+ pStart: (taskInfo.estimatedStartDate as Timestamp).toLocalDateTime().dateString,
+ pEnd: (taskInfo.estimatedCompletionDate as Timestamp).toLocalDateTime().dateString,
+ pPlanStart: (taskInfo.estimatedStartDate as Timestamp).toLocalDateTime().dateString,
+ pPlanEnd: (taskInfo.estimatedCompletionDate as Timestamp).toLocalDateTime().dateString,
+ pClass: taskInfo.workEffortTypeId == milestoneWorkEffortTypeId ? 'gmilestone' : 'gtaskgreen',
+ pLink: taskInfo.url,
+ pMile: taskInfo.workEffortTypeId == milestoneWorkEffortTypeId ? 1 : 0,
+ pRes: taskInfo.resource,
+ pComp: taskInfo.completion,
+ pGroup: 0,
+ pParent: taskInfo.phaseNr,
+ pOpen: taskInfo.workEffortTypeId == milestoneWorkEffortTypeId ? 0 : 1,
+ pDepend: taskInfo.preDecessor ?: '',
+ ]
+ }
+ }
+ }
+}
+
+context.phaseTaskListJson = JsonOutput.toJson(ganttItems)
diff --git a/projectmgr/template/project/GanttChart.ftl b/projectmgr/template/project/GanttChart.ftl
new file mode 100644
index 000000000..cb08a3697
--- /dev/null
+++ b/projectmgr/template/project/GanttChart.ftl
@@ -0,0 +1,26 @@
+<#-- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -->
+<#--
+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.
+-->
+
+<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
+
+<input id="ofbizGantItemsJson" type="hidden" value="${phaseTaskListJson}"/>
+
+<script type="text/javascript" src="/projectmgr/node_modules/jsgantt-improved/dist/jsgantt.js"></script>
+<script type="text/javascript" src="/projectmgr/static/projectmgr.js"></script>
diff --git a/projectmgr/webapp/projectmgr/WEB-INF/controller.xml b/projectmgr/webapp/projectmgr/WEB-INF/controller.xml
index 06d009bad..73800075a 100644
--- a/projectmgr/webapp/projectmgr/WEB-INF/controller.xml
+++ b/projectmgr/webapp/projectmgr/WEB-INF/controller.xml
@@ -34,6 +34,11 @@
<response name="success" type="view" value="main"/>
</request-map>
+ <request-map uri="ganttChart">
+ <security https="true" auth="true"/>
+ <response name="success" type="view" value="ganttChart"/>
+ </request-map>
+
<request-map uri="ListSubProjects">
<security https="true" auth="true"/>
<response name="success" type="view" value="ListSubProjects"/>
@@ -692,6 +697,7 @@
<view-map name="EditPartyRates" type="screen" page="component://projectmgr/widget/ResourceScreens.xml#EditPartyRates"/>
<view-map name="main" type="screen" page="component://projectmgr/widget/CommonScreens.xml#Main"/>
+ <view-map name="ganttChart" type="screen" page="component://projectmgr/widget/ProjectScreens.xml#ganttChart"/>
<view-map name="ListSubProjects" type="screen" page="component://projectmgr/widget/ProjectScreens.xml#ListSubProjects"/>
<view-map name="FindResource" type="screen" page="component://projectmgr/widget/ResourceScreens.xml#FindResource"/>
<view-map name="FindProject" type="screen" page="component://projectmgr/widget/ProjectScreens.xml#FindProject"/>
diff --git a/projectmgr/webapp/projectmgr/WEB-INF/web.xml b/projectmgr/webapp/projectmgr/WEB-INF/web.xml
index d86c38317..2aa29a5d7 100644
--- a/projectmgr/webapp/projectmgr/WEB-INF/web.xml
+++ b/projectmgr/webapp/projectmgr/WEB-INF/web.xml
@@ -64,7 +64,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</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>
diff --git a/projectmgr/webapp/projectmgr/package-lock.json b/projectmgr/webapp/projectmgr/package-lock.json
new file mode 100644
index 000000000..9dfcbfc20
--- /dev/null
+++ b/projectmgr/webapp/projectmgr/package-lock.json
@@ -0,0 +1,38 @@
+{
+ "name": "ofbiz-projectmgr",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "ofbiz-projectmgr",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "jsgantt-improved": "^3.0.0"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "24.12.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz",
+ "integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
+ "node_modules/jsgantt-improved": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/jsgantt-improved/-/jsgantt-improved-3.0.0.tgz",
+ "integrity": "sha512-0OtLBSmb5e0WAroRhp0sT+hJBSYM9x0zsGxXpv+RSVpoQ4HovE5+G5c0SDD+1ogXld9dkJtbDGCmvJQYhxCxwA==",
+ "license": "ISC",
+ "dependencies": {
+ "@types/node": "^24.3.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "license": "MIT"
+ }
+ }
+}
diff --git a/projectmgr/webapp/projectmgr/package.json b/projectmgr/webapp/projectmgr/package.json
new file mode 100644
index 000000000..22902caa1
--- /dev/null
+++ b/projectmgr/webapp/projectmgr/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "ofbiz-projectmgr",
+ "description": "ofbiz-plugins projectmgr NPM dependencies configuration",
+ "repository": "https://github.com/apache/ofbiz-plugins",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "jsgantt-improved": "^3.0.0"
+ }
+}
diff --git a/projectmgr/webapp/projectmgr/static/projectmgr.css b/projectmgr/webapp/projectmgr/static/projectmgr.css
new file mode 100644
index 000000000..ac6061151
--- /dev/null
+++ b/projectmgr/webapp/projectmgr/static/projectmgr.css
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/* This CSS file is used for the Project Manager component. */
+
+/* Remove any margins that my have been set on all divs by the themes, such as Rainbowstone */
+.gchartcontainer div {
+ margin: unset
+}
diff --git a/projectmgr/webapp/projectmgr/static/projectmgr.js b/projectmgr/webapp/projectmgr/static/projectmgr.js
new file mode 100644
index 000000000..f506ffd42
--- /dev/null
+++ b/projectmgr/webapp/projectmgr/static/projectmgr.js
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+const ganttItemsJson = document.getElementById("ofbizGantItemsJson").value;
+const ganttItems = JSON.parse(ganttItemsJson);
+
+const g = new JSGantt.GanttChart(document.getElementById('GanttChartDIV'), 'day');
+g.setShowRes(1); // Show/Hide Resource (0/1)
+g.setShowDur(1); // Show/Hide Duration (0/1)
+g.setShowComp(1); // Show/Hide % Complete(0/1)
+g.setShowTaskInfoLink(1);
+g.setShowTaskInfoNotes(0)
+
+g.setDateTaskTableDisplayFormat('dd mon yyyy');
+g.setDayMajorDateDisplayFormat('dd mon');
+
+for (t of ganttItems) {
+ g.AddTaskItem(
+ new JSGantt.TaskItem(t.pID, t.pName, t.pStart, t.pEnd, t.pClass, t.pLink, t.pMile, t.pRes, t.pComp,
+ t.pGroup, t.pParent, t.pOpen, t.pDepend, "", "", g)
+ );
+}
+
+g.Draw();
diff --git a/projectmgr/widget/CommonScreens.xml b/projectmgr/widget/CommonScreens.xml
index 7216090d1..647770272 100644
--- a/projectmgr/widget/CommonScreens.xml
+++ b/projectmgr/widget/CommonScreens.xml
@@ -39,6 +39,7 @@ under the License.
<!-- layoutSettings.headerImageUrl can be used to specify an application specific logo; if not set,
then the global layoutSettings.commonHeaderImageUrl (specified in GlobalDecorator) will be used. -->
<!--<set field="layoutSettings.headerImageUrl" value="/images/ofbiz_logo.png" global="true"/>-->
+ <set field="layoutSettings.styleSheets[]" value="/projectmgr/static/projectmgr.css" global="true"/>
<set field="activeApp" value="projectmgr" global="true"/>
<set field="applicationMenuName" value="ProjectMgrAppBar" global="true"/>
<set field="applicationMenuLocation" value="${parameters.mainMenuLocation}" global="true"/>
diff --git a/projectmgr/widget/ProjectMenus.xml b/projectmgr/widget/ProjectMenus.xml
index cab8eb9e5..0a0b3f163 100644
--- a/projectmgr/widget/ProjectMenus.xml
+++ b/projectmgr/widget/ProjectMenus.xml
@@ -83,6 +83,14 @@
"projectId", projectId));
return result.get("hasPermission"); }" type="Boolean"/>
</actions>
+ <menu-item name="ganttchart" title="${uiLabelMap.ProjectMgrGanttChart}">
+ <condition>
+ <if-compare field="hasViewPermission" operator="equals" value="true"/>
+ </condition>
+ <link target="ganttChart">
+ <parameter param-name="projectId"/>
+ </link>
+ </menu-item>
<menu-item name="projectView" title="${uiLabelMap.ProjectMgrProjectSummary}">
<condition>
<if-compare field="hasViewPermission" operator="equals" value="true"/>
diff --git a/projectmgr/widget/ProjectScreens.xml b/projectmgr/widget/ProjectScreens.xml
index fddf47acd..0ee555b9f 100644
--- a/projectmgr/widget/ProjectScreens.xml
+++ b/projectmgr/widget/ProjectScreens.xml
@@ -419,6 +419,29 @@ under the License.
</widgets>
</section>
</screen>
+ <screen name="ganttChart">
+ <section>
+ <actions>
+ <set field="titleProperty" value="ProjectMgrGanttChart"/>
+ <set field="tabButtonItem" value="ganttchart"/>
+ <set field="layoutSettings.styleSheets[]" value="/projectmgr/node_modules/jsgantt-improved/dist/jsgantt.css" global="true"/>
+ <set field="layoutSettings.styleSheets[]" value="/projectmgr/static/projectmgr.css" global="true"/>
+ <script location="component://projectmgr/src/main/groovy/org/apache/ofbiz/projectmgr/GanttChart.groovy"/>
+ </actions>
+ <widgets>
+ <label text="${project}"/>
+ <decorator-screen name="CommonProjectDecorator" location="${parameters.mainDecoratorLocation}">
+ <decorator-section name="body">
+ <screenlet title="${uiLabelMap.PageTitleProjectGanttChart}">
+ <platform-specific>
+ <html><html-template multi-block="true" location="component://projectmgr/template/project/GanttChart.ftl"/></html>
+ </platform-specific>
+ </screenlet>
+ </decorator-section>
+ </decorator-screen>
+ </widgets>
+ </section>
+ </screen>
<screen name="SubProjectsInfo">
<section>
<actions>
@@ -957,6 +980,8 @@ under the License.
<section>
<actions>
<property-map resource="ProjectMgrUiLabels" map-name="uiLabelMap" global="true"/>
+ <set field="layoutSettings.styleSheets[]" value="/projectmgr/node_modules/jsgantt-improved/dist/jsgantt.css" global="true"/>
+ <set field="layoutSettings.styleSheets[]" value="/projectmgr/static/projectmgr.css" global="true"/>
<entity-condition entity-name="WorkEffortPartyAssignByGroup" list="projects" filter-by-date="true">
<condition-list combine="and">
<condition-expr field-name="partyId" from-field="userLogin.partyId"/>
@@ -974,6 +999,7 @@ under the License.
<actions>
<set field="projectId" from-field="project.workEffortId"/>
<set field="parameters.projectId" from-field="project.workEffortId"/>
+ <script location="component://projectmgr/src/main/groovy/org/apache/ofbiz/projectmgr/GanttChart.groovy"/>
<service service-name="getProject" result-map="result">
<field-map field-name="projectId" from-field="projectId"/>
</service>
@@ -1016,6 +1042,12 @@ under the License.
</widgets>
</section>
</container>
+ <container style="clear"/>
+ <screenlet title="${uiLabelMap.PageTitleProjectGanttChart}">
+ <platform-specific>
+ <html><html-template multi-block="true" location="component://projectmgr/template/project/GanttChart.ftl"/></html>
+ </platform-specific>
+ </screenlet>
</widgets>
</section>
</iterate-section>