Commit cd7f67ca authored by Frank Bergmann's avatar Frank Bergmann

Initial Import

parents
Pipeline #284 failed with stages
<?xml version="1.0"?>
<!-- Generated by the OpenACS Package Manager -->
<package key="intranet-gantt-editor" url="http://openacs.org/repository/apm/packages/intranet-gantt-editor" type="apm_application">
<package-name>]project-open[ Gantt Editor</package-name>
<pretty-plural>]project-open[ Gantt Editor</pretty-plural>
<initial-install-p>f</initial-install-p>
<singleton-p>t</singleton-p>
<implements-subsite-p>f</implements-subsite-p>
<inherit-templates-p>f</inherit-templates-p>
<auto-mount>intranet-gantt-editor</auto-mount>
<version name="0.1d" url="http://openacs.org/repository/download/apm/intranet-gantt-editor-0.1d.apm">
<owner url="mailto:frank.bergmann@project-open.com">Frank Bergmann</owner>
<summary>Gantt editor</summary>
<vendor url="http://www.project-open.com/">]project-open[</vendor>
<description format="text/plain">Sencha implementation of a Gantt editor similar to ProjectLibre and MS-Project.</description>
<maturity>0</maturity>
<provides url="intranet-gantt-editor" version="0.1d"/>
<callbacks>
</callbacks>
<parameters>
<!-- No version parameters -->
</parameters>
</version>
</package>
<div id=@gantt_editor_id@>
<script type='text/javascript'>
// Ext.Loader.setConfig({enabled: true});
Ext.Loader.setPath('Ext.ux', '/sencha-v411/examples/ux');
Ext.Loader.setPath('PO.model', '/sencha-core/model');
Ext.Loader.setPath('PO.store', '/sencha-core/store');
Ext.Loader.setPath('PO.class', '/sencha-core/class');
Ext.Loader.setPath('PO.view.gantt', '/sencha-core/view/gantt');
Ext.Loader.setPath('PO.controller', '/sencha-core/controller');
Ext.require([
'Ext.data.*',
'Ext.grid.*',
'Ext.tree.*',
'Ext.ux.CheckColumn',
'PO.class.CategoryStore',
'PO.model.timesheet.TimesheetTask',
'PO.controller.StoreLoadCoordinator',
'PO.store.project.ProjectStatusStore',
'PO.store.timesheet.TaskTreeStore'
]);
function launchGanttEditor(){
var taskTreeStore = Ext.StoreManager.get('taskTreeStore');
var statusStore = Ext.StoreManager.get('projectStatusStore');
var ganttTreePanel = Ext.create('PO.view.gantt.GanttTreePanel', {
width: 300,
region: 'west',
});
var ganttDrawComponent = Ext.create('PO.view.gantt.GanttDrawComponent', {
ganttTreePanel: ganttTreePanel,
region: 'center',
viewBox: false,
gradients: [{
id: 'gradientId',
angle: 66,
stops: {
0: { color: '#ddf' },
100: { color: '#00A' }
}
}, {
id: 'gradientId2',
angle: 0,
stops: {
0: { color: '#590' },
20: { color: '#599' },
100: { color: '#ddd' }
}
}]
});
var ganttTimeline = Ext.create('PO.view.gantt.GanttTimeline', {
ganttTreePanel: ganttTreePanel,
title: false,
layout: 'border',
region: 'south',
width: 300,
height: 50
});
var ganttRightSide = Ext.create('Ext.panel.Panel', {
title: false,
layout: 'border',
region: 'center',
collapsible: false,
width: 300,
height: 300,
defaults: { // These defaults produce a bar to resize the timeline
collapsible: true,
split: true,
bodyPadding: 0
},
items: [
ganttDrawComponent,
ganttTimeline
]
});
// Outer Gantt editor jointing the two parts (TreePanel + Draw)
var screenSize = Ext.getBody().getViewSize(); // Size calculation based on specific ]po[ layout
var sideBarSize = Ext.get('sidebar').getSize();
var width = screenSize.width - sideBarSize.width - 95;
var height = screenSize.height - 280;
var ganttEditor = Ext.create('PO.view.gantt.GanttButtonPanel', {
width: width,
height: height,
resizable: true, // Add handles to the panel, so the user can change size
items: [
ganttRightSide,
ganttTreePanel
],
renderTo: '@gantt_editor_id@'
});
// Initiate controller
var sideBarTab = Ext.get('sideBarTab');
var renderDiv = Ext.get('@gantt_editor_id@');
var ganttButtonController = Ext.create('PO.controller.gantt.GanttButtonController', {
'renderDiv': renderDiv,
'ganttEditor': ganttEditor,
'ganttButtonController': ganttButtonController,
'ganttTreePanel': ganttTreePanel,
'ganttDrawComponent': ganttDrawComponent,
'ganttTimeline': ganttTimeline
});
ganttButtonController.init(this).onLaunch(this);
// Handle collapsable side menu
sideBarTab.on('click', ganttButtonController.onSideBarResize, ganttButtonController);
Ext.EventManager.onWindowResize(ganttButtonController.onWindowsResize, ganttButtonController); // Deal with resizing the main window
};
Ext.onReady(function() {
Ext.QuickTips.init();
var statusStore = Ext.create('PO.store.project.ProjectStatusStore');
var taskTreeStore = Ext.create('PO.store.timesheet.TaskTreeStore');
// Use a "store coodinator" in order to launchGanttEditor() only
// if all stores have been loaded:
var coordinator = Ext.create('PO.controller.StoreLoadCoordinator', {
stores: [
'projectStatusStore',
'taskTreeStore'
],
listeners: {
load: function() {
// Check if the application was launched before
if ("boolean" == typeof this.loadedP) { return; }
// Launch the actual application.
launchGanttEditor();
// Mark the application as launched
this.loadedP = true;
}
}
});
// Load stores that need parameters
taskTreeStore.getProxy().extraParams = { project_id: @project_id@ };
taskTreeStore.load({
callback: function() {
console.log('PO.store.timesheet.TaskTreeStore: loaded');
}
});
});
</script>
</div>
# /packages/intranet-gantt-editor/lib/task-editor.tcl
#
# Copyright (C) 2012 ]project-open[
#
# All rights reserved. Please check
# http://www.project-open.com/license/ for details.
# ----------------------------------------------------------------------
#
# ---------------------------------------------------------------------
# The following variables are expected in the environment
# defined by the calling /tcl/*.tcl libary:
# project_id
# project_id may be overwritten by SQLs below
set main_project_id $project_id
# Create a random ID for the gantt editor
set gantt_editor_rand [expr round(rand() * 100000000.0)]
set gantt_editor_id "gantt_editor_$gantt_editor_rand"
<div id=@task_editor_id@>
<script type='text/javascript'>
// Ext.Loader.setConfig({enabled: true});
Ext.Loader.setPath('Ext.ux', '/sencha-v411/examples/ux');
Ext.Loader.setPath('PO.model', '/sencha-core/model');
Ext.Loader.setPath('PO.store', '/sencha-core/store');
Ext.Loader.setPath('PO.class', '/sencha-core/class');
Ext.Loader.setPath('PO.controller', '/sencha-core/controller');
Ext.require([
'Ext.data.*',
'Ext.grid.*',
'Ext.tree.*',
'Ext.ux.CheckColumn',
'PO.class.CategoryStore',
'PO.model.timesheet.TimesheetTask',
'PO.controller.StoreLoadCoordinator',
'PO.store.timesheet.TaskStatusStore',
'PO.store.timesheet.TaskTreeStore'
]);
function launchTaskEditorTreePanel(){
var taskTreeStore = Ext.StoreManager.get('taskTreeStore');
var taskStatusStore = Ext.StoreManager.get('taskStatusStore');
var rowEditing = Ext.create('Ext.grid.plugin.RowEditing', {
clicksToMoveEditor: 2,
autoCancel: false
});
var tree = Ext.create('Ext.tree.Panel', {
title: 'Core Team Projects',
width: 500,
height: 300,
renderTo: '@task_editor_id@',
collapsible: true,
useArrows: true,
rootVisible: false,
store: taskTreeStore,
multiSelect: true,
singleExpand: false,
// Enable in-line row editing.
plugins: [rowEditing],
// Enabled drag-and-drop for the tree. Yes, that's all...
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop',
containerScroll: true
}
},
// the 'columns' property is now 'headers'
columns: [{
xtype: 'treecolumn', //this is so we know which column will show the tree
text: 'Task',
flex: 2,
sortable: true,
dataIndex: 'project_name',
editor: {
allowBlank: false
}
},{
text: 'Assigned To',
flex: 1,
dataIndex: 'user',
sortable: true,
editor: {
allowBlank: true
}
},{
text: 'Start',
xtype: 'datecolumn',
format: 'Y-m-d',
// format: 'Y-m-d H:i:s', // 2000-01-01 00:00:00+01
flex: 1,
dataIndex: 'start_date',
sortable: true,
editor: {
allowBlank: false
}
},{
text: 'End',
xtype: 'datecolumn',
format: 'Y-m-d',
flex: 1,
dataIndex: 'end_date_date',
sortable: true,
editor: {
allowBlank: false
}
},{
text: 'Status',
flex: 1,
dataIndex: 'project_status_id',
sortable: true,
renderer: function(value){
var model = taskStatusStore.getById(value);
var result = model.get('category');
return result;
},
editor: {
xtype: 'combo',
store: taskStatusStore,
displayField: 'category',
valueField: 'category_id',
}
}, {
xtype: 'checkcolumn',
header: 'Done',
dataIndex: 'done',
width: 40,
stopSelection: false,
editor: {
xtype: 'checkbox',
cls: 'x-grid-checkheader-editor'
}
}],
listeners: {
'selectionchange': function(view, records) {
if (1 == records.length) {
// Exactly one record enabled
var record = records[0];
tree.down('#removeTask').setDisabled(!record.isLeaf());
} else {
// Zero or two or more records enabled
tree.down('#removeTask').setDisabled(true);
}
}
},
// Toolbar for adding and deleting tasks
tbar: [{
text: 'Add Task',
iconCls: 'task-add',
handler : function() {
rowEditing.cancelEdit();
// Create a model instance
var r = Ext.create('PO.model.timesheet.TimesheetTask', {
project_name: "New Task",
project_nr: "task_0018",
parent_id: "709261",
company_id: "500633",
start_date: "2013-09-19 12:00:00+02",
end_date: "2013-09-20 12:00:00+02",
percent_completed: "0",
project_status_id: "76",
project_type_id: "100"
});
taskTreeStore.sync();
var selectionModel = tree.getSelectionModel();
var lastSelected = selectionModel.getLastSelected();
// ToDo: Appending the new task at the lastSelected does't work for some reasons.
// Also, the newly added task should be a "task" and not a folder.
var root = taskTreeStore.getRootNode();
// root.appendChild(r);
lastSelected.appendChild(r);
}
}, {
itemId: 'removeTask',
text: 'Remove Task',
iconCls: 'task-remove',
handler: function() {
rowEditing.cancelEdit();
var selectionModel = tree.getSelectionModel();
var lastSelected = selectionModel.getLastSelected();
var parent = lastSelected.parentNode;
var lastSelectedIndex = parent.indexOf(lastSelected);
// Remove the selected element
lastSelected.remove();
var newNode = parent.getChildAt(lastSelectedIndex);
if (typeof(newNode) == "undefined") {
lastSelectedIndex = lastSelectedIndex -1;
if (lastSelectedIndex < 0) { lastSelectedIndex = 0; }
newNode = parent.getChildAt(lastSelectedIndex);
}
if (typeof(newNode) == "undefined") {
// lastSelected was the last child of it's parent, so select the parent.
selectionModel.select(parent);
} else {
newNode = parent.getChildAt(lastSelectedIndex);
selectionModel.select(newNode);
}
},
disabled: true
}]
});
};
Ext.onReady(function() {
Ext.QuickTips.init();
var taskStatusStore = Ext.create('PO.store.timesheet.TaskStatusStore');
var taskTreeStore = Ext.create('PO.store.timesheet.TaskTreeStore');
// Use a "store coodinator" in order to launchTaskEditorTreePanel() only
// if all stores have been loaded:
var coordinatior = Ext.create('PO.controller.StoreLoadCoordinator', {
stores: [
'taskStatusStore',
'taskTreeStore'
],
listeners: {
load: function() {
// Launch the actual application.
launchTaskEditorTreePanel();
}
}
});
// Load stores that need parameters
taskTreeStore.getProxy().extraParams = { project_id: @project_id@ };
taskTreeStore.load();
});
</script>
</div>
<if "" ne @data_list@>
</if>
# /packages/sencha-task-editor/lib/task-editor.tcl
#
# Copyright (C) 2012 ]project-open[
#
# All rights reserved. Please check
# http://www.project-open.com/license/ for details.
# ----------------------------------------------------------------------
#
# ---------------------------------------------------------------------
# The following variables are expected in the environment
# defined by the calling /tcl/*.tcl libary:
# project_id
set data_list {}
# project_id may be overwritten by SQLs below
set main_project_id $project_id
# Create a random ID for the task_editor
set task_editor_rand [expr round(rand() * 100000000.0)]
set task_editor_id "task_editor_$task_editor_rand"
-- /packages/intranet-gantt-editor/sql/postgresql/intranet-gantt-editor-create.sql
--
-- Copyright (c) 2010 ]project-open[
--
-- All rights reserved. Please check
-- http://www.project-open.com/license/ for details.
--
-- @author frank.bergmann@project-open.com
-- ------------------------------------------------------------
-- Gantt Editor Portlet
-- ------------------------------------------------------------
SELECT im_component_plugin__new (
null, -- plugin_id
'im_component_plugin', -- object_type
now(), -- creation_date
null, -- creation_user
null, -- creation_ip
null, -- context_id
'Gantt Editor', -- plugin_name
'intranet-gantt-editor', -- package_name
'top', -- location
'/intranet/projects/view', -- page_url
null, -- view_name
10, -- sort_order
'gantt_editor_portlet -project_id $project_id'
);
SELECT acs_permission__grant_permission(
(select plugin_id from im_component_plugins where plugin_name = 'Gantt Editor' and package_name = 'intranet-gantt-editor'),
(select group_id from groups where group_name = 'Employees'),
'read'
);
---------------------------------------------------------
-- REST Data-Sources
--
-- These reports are portfolio-planner specific, so we do
-- not have to add them to sencha-core.
---------------------------------------------------------
-- List all intra-project dependencies on the server
--
SELECT im_report_new (
'REST Intra-Project Task Dependencies', -- report_name
'rest_intra_project_task_dependencies', -- report_code
'sencha-core', -- package_key
220, -- report_sort_order
(select menu_id from im_menus where label = 'reporting-rest'), -- parent_menu_id
''
);
update im_reports set
report_description = 'Returns the list of intra-project dependencies',
report_sql = '
select d.dependency_id as id,
d.*,
main_project.project_id as main_project_id_one,
main_project.project_name as main_project_name_one,
p_one.project_id as task_one_id,
p_one.project_name as task_one_name,
p_one.start_date as task_one_start_date,
p_one.end_date as task_one_end_date,
p_two.project_id as task_two_id,
p_two.project_name as task_two_name,
p_two.start_date as task_two_start_date,
p_two.end_date as task_two_end_date
from im_timesheet_task_dependencies d,
im_projects p_one,
im_projects p_two,
im_projects main_project
where main_project.project_id = %main_project_id% and
p_one.project_id = d.task_id_one and
p_two.project_id = d.task_id_two and
p_one.tree_sortkey betweeen main_project.tree_sortkey and tree_right(main_project.tree_sortkey) and
p_two.tree_sortkey betweeen main_project.tree_sortkey and tree_right(main_project.tree_sortkey)
order by p_one.tree_sortkey, p_two.tree_sortkey
'
where report_code = 'rest_intra_project_task_dependencies';
-- Relatively permissive
SELECT acs_permission__grant_permission(
(select menu_id from im_menus where label = 'rest_intra_project_task_dependencies'),
(select group_id from groups where group_name = 'Employees'),
'read'
);
-- /packages/intranet-gantt-editor/sql/postgresql/intranet-gantt-editor-drop.sql
--
-- Copyright (c) 2010 ]project-open[
--
-- All rights reserved. Please check
-- http://www.project-open.com/license/ for details.
--
-- @author frank.bergmann@project-open.com
select im_component_plugin__del_module('intranet-gantt-editor');
select im_menu__del_module('intranet-gantt-editor');
# /packages/intranet-gantt-editor/tcl/intranet-gantt-editor.tcl
#
# Copyright (C) 2010-2013 ]project-open[
#
# All rights reserved. Please check
# http://www.project-open.com/license/ for details.
ad_library {
Gantt Editor library.
@author frank.bergmann@project-open.com
}
ad_proc -public gantt_editor_portlet {
-project_id:required
} {
Returns a HTML code with a Gantt editor for the project.
} {
# Sencha check and permissions
if {![im_sencha_extjs_installed_p]} { return "" }
im_sencha_extjs_load_libraries
set params [list \
[list project_id $project_id] \
]
set result [ad_parse_template -params $params "/packages/intranet-gantt-editor/lib/gantt-editor"]
return [string trim $result]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment