Commit d8ff6b51 authored by Frank Bergmann's avatar Frank Bergmann

Initial Import

parents
Pipeline #612 failed with stages
<?xml version="1.0"?>
<!-- Generated by the OpenACS Package Manager -->
<package key="sencha-core" url="http://openacs.org/repository/apm/packages/sencha-core" type="apm_application">
<package-name>]project-open[ Sencha Core</package-name>
<pretty-plural>]project-open[ Sencha Core</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>sencha-core</auto-mount>
<version name="0.1d" url="http://openacs.org/repository/download/apm/sencha-core-0.1d.apm">
<owner url="mailto:frank.bergmann@project-open.com">Frank Bergmann</owner>
<summary>Core ]po[ Sencha functionality that is reusable between different ]po[ Sencha applications</summary>
<vendor url="http://www.project-open.com/">]project-open[</vendor>
<description format="text/plain">Contains models and stores for ]po[ core objects.</description>
<maturity>0</maturity>
<provides url="sencha-core" version="0.1d"/>
<callbacks>
</callbacks>
<parameters>
<!-- No version parameters -->
</parameters>
</version>
</package>
/**
* sencha-core/www/class/CategoryStore.js
* Subclass for Categories
*
* Copyright (C) 2013, ]project-open[
* @author Frank Bergmann (frank.bergmann@project-open.com)
* @creation-date 2013-11-29
* @cvs-id $Id$
*/
/*
* Create a specific store for categories.
* The subclass contains a special lookup function.
*/
Ext.define('PO.class.CategoryStore', {
extend: 'Ext.data.Store',
category_from_id: function(category_id) {
if (null == category_id || '' == category_id) { return ''; }
var result = 'Category #' + category_id;
var rec = this.findRecord('category_id',category_id);
if (rec == null || typeof rec == "undefined") { return result; }
return rec.get('category_translated');
},
fill_tree_category_translated: function(store) { // Concat the tree category names. It is useful to order by name and level
store.each(function(record){
var tree_sortkey = record.get('tree_sortkey');
var lon = record.get('tree_sortkey').length;
var tree_category = '';
while (lon > 0) {
lon = lon - 8;
tree_category = store.findRecord('category_id','' + parseInt(tree_sortkey.substr(lon,8),10)).get('category_translated') + tree_category;
}
record.set('tree_category_translated', tree_category);
});
},
validateLevel: function(value,nullvalid) { //Validate the combo value. No level with sublevel is permitted.
if (nullvalid && Ext.isEmpty(value)) {
return true;
}
if (!nullvalid && Ext.isEmpty(value)) {
return 'Obligatorio';
}
try {
var validate = true;
var record = this.getById(value);
var record_field_value = record.get('tree_sortkey');
var record_field_length = record_field_value.length;
this.clearFilter()
this.each(function(record){
var store_field_value = record.get('tree_sortkey');
var store_field_length = store_field_value.length;
if (store_field_length > record_field_length && store_field_value.substring(0,record_field_length) == record_field_value) {
validate = 'No permitido';
return validate;
}
}
);
return validate;
} catch(err) {
return 'Obligatorio';
}
},
addBlank: function() { // Add blank value to the store. It is used to white selecction in comboboxes
var categoryVars = {category_id: '', category_translated: null, sort_order: '0'};
var category = Ext.ModelManager.create(categoryVars, 'TicketBrowser.Category');
this.add(category);
},
getParent: function(value) {//Get category parent ID
if (!Ext.isEmpty(value)) {
var record = this.getById(value);
if (!Ext.isEmpty(record)) {
var record_field_value = record.get('tree_sortkey');
var record_field_length = record_field_value.length;
this.clearFilter();
var parent_id = this.findRecord('tree_sortkey','' + parseInt(record_field_value.substr(0,record_field_length - 8),10)).get('category_id');
return parent_id;
}
}
return '';
}
});
// /sencha-core/www/controller/StoreLoadCoordinator.js
//
// Copyright (C) 2013 ]project-open[
//
// All rights reserved. Please see
// http://www.project-open.com/license/ for details.
//
/*
* This coodinator is initiated with:
* stores: A list of stores that need to be loaded and
* listeners: {
* load: function() {}
* }
* It calls the listener function once all stores
* have been sussessfully loaded.
*
* The StoreLoadCoordinator plays it's role after
* Ext.Loader has finished loading classes and before
* the start of the actual application.
*/
Ext.define('PO.controller.StoreLoadCoordinator', {
mixins: {
observable: 'Ext.util.Observable'
},
resetStoreLoadStates: function() {
this.storeLoadStates = {};
Ext.each(this.stores, function(storeId) {
this.storeLoadStates[storeId] = false;
}, this);
},
isLoadingComplete: function() {
for (var i=0; i<this.stores.length; i++) {
var key = this.stores[i];
if (this.storeLoadStates[key]==false) {
return false;
}
}
return true;
},
onStoreLoad: function(store, records, successful, eOpts, storeName) {
this.storeLoadStates[store.storeId] = true;
if (this.isLoadingComplete()==true) {
this.fireEvent('load');
// this.resetStoreLoadStates();
}
},
constructor: function (config) {
this.mixins.observable.constructor.call(this, config);
this.resetStoreLoadStates();
Ext.each(this.stores, function(storeId) {
var store = Ext.StoreManager.lookup(storeId);
store.on('load', Ext.bind(this.onStoreLoad, this, [storeId], true));
}, this);
this.addEvents('load');
}
});
/*
* Categories are used everywhere in the system
* to represent states and types of objects and
* any finite list of options.
*
* Categories are used as stores for form fields,
* so we need "text" and "value" fields for those.
*
* Categories are hierarchical.
* Categories are read-only.
*/
Ext.define('PO.model.category.Category', {
extend: 'Ext.data.Model',
idProperty: 'category_id', // The primary key of the category
valueProperty: 'category_translated',
fields: [
'id', // same as category_id
'category_id', // primary key - constant
'category', // Name of the category
'category_type', // type of category
'category_translated', // Name of the category in the user locale
'category_description', // Lengthy description in English
'enabled_p', // 't' = enabled, 'f' = disabled
'sort_order', // Order to show on screen
'aux_int1', //
'aux_int2', //
'aux_string1', //
'aux_string2'
]
// Categories don't need a separate proxy
// because they are alway used as part of a store.
});
/*
{type: 'string', name: 'indent_class', // Determine the indentation level for each element in the tree
convert: function(value, record) {
var category = record.get('category_translated');
var indent = (record.get('tree_sortkey').length / 8) - 1;
return 'extjs-indent-level-' + indent;
}
}
{ name: 'text', // 'text' is used by Select field as pretty name
convert: function(value, record) { return record.get('category'); }
},
{ name: 'value', // 'value' is used by Select field as value
convert: function(value, record) { return record.get('category_id'); }
}
*/
Ext.define('PO.model.Note', {
extend: 'Ext.data.Model',
config: {
fields: [
'id',
'note',
'object_id',
'note_status_id',
'note_type_id'
],
proxy: {
type: 'rest',
url: '/intranet-rest/im_note',
appendId: true, // Append the object_id: ../im_ticket/<object_id>
timeout: 300000,
extraParams: {
format: 'json', // Tell the ]po[ REST to return JSON data.
deref_p: '1',
columns: 'note,note_type_id'
},
reader: {
type: 'json', // Tell the Proxy Reader to parse JSON
root: 'data', // Where do the data start in the JSON file?
totalProperty: 'total' // Total number of tickets for pagination
},
writer: {
type: 'json' // Allow Sencha to write ticket changes
}
}
}
});
Ext.define('PO.model.Project', {
extend: 'Ext.data.Model',
config: {
fields: [
'id',
'project_id', // The primary key or object_id of the project
'creation_user', // User_id of the guy creating the project
'project_name', // The name of the project
'project_nr', // The short name of the project.
'project_path', // The short name of the project.
'parent_id', // The parent of the project or NULL for a main project
'tree_sortkey', // A strange bitstring that determines the hierarchical position
'company_id', // Company for whom the project has been created
'project_status_id', // 76=open, 81=closed, ...
'project_type_id', // 100=Task, 101=Ticket, 2501=Consulting Project, ...
'start_date', // '2001-01-01'
'end_date',
'project_lead_id', // Project manager
'percent_completed', // 0 - 100: Defines what has already been done.
'on_track_status_id', // 66=green, 67=yellow, 68=red
'description',
'note',
'level', // 0 for a main project, 1 for a sub-project etc.
// ------------ // Denormalized fields from suitable queries
'project_status', // denormalized project_status_id (English), may not be set depending on query
'project_type', // denormalized project_type_id (English), may not be set depending on query
'company_name', // denormalized company_id
'project_lead_name', // Project manager
// ------------ // Special fields only used by certain quieres. ToDo: Different model?
'hours_total', // may not be set depending on query
'hours_for_user', // may not be set depending on query
'hours_for_user_date', // may not be set depending on query
{ name: 'indent', // A &nbsp; sequence representing the project indentation
convert: function(value, record) {
var level = record.get('level');
var result = '';
while (level > 0) {
result = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' + result;
level = level - 1;
}
return result;
}
}
],
proxy: {
type: 'rest',
url: '/intranet-rest/im_project',
appendId: true, // Append the object_id: ../im_ticket/<object_id>
timeout: 300000,
extraParams: {
format: 'json', // Tell the ]po[ REST to return JSON data.
deref_p: '1'
},
reader: {
type: 'json', // Tell the Proxy Reader to parse JSON
root: 'data', // Where do the data start in the JSON file?
totalProperty: 'total' // Total number of tickets for pagination
},
writer: {
type: 'json' // Allow Sencha to write ticket changes
}
}
}
});
Ext.define('PO.model.Hour', {
extend: 'Ext.data.Model',
config: {
fields: [
'id', // Same as hour_id
'hour_id', // Unique ID taken from im_hours_seq
'user_id', // Who logged the hours?
'project_id', // On which project or task?
'day', // Which day (format: date, not timestamptz)
'hours', // How many hours were logged?
'note', // Comment for the logged hours
'internal_note', // Comment hidden from customers (rarely used)
'cost_id', // Link to cost item created to represent the internal cost of providing hours
'invoice_id', // Invoice where hours have been billed to customer (optional)
'conf_object_id', // Workflow "confirmation object" for timesheet approval (optional)
'material_id', // Type of service provided during hours (rarely used)
'days', // Hours converted into days for daily invoicing (rarely used)
{ name: 'date',
convert: function(value, record) {
return record.get('day').substring(0,10);
}
}
],
proxy: {
type: 'rest',
url: '/intranet-rest/im_hour',
appendId: true, // Append the object_id: ../im_ticket/<object_id>
timeout: 300000,
extraParams: {
format: 'json' // Tell the ]po[ REST to return JSON data.
},
reader: {
type: 'json', // Tell the Proxy Reader to parse JSON
root: 'data', // Where do the data start in the JSON file?
totalProperty: 'total' // Total number of tickets for pagination
},
writer: {
type: 'json' // Allow Sencha to write ticket changes
}
}
}
});
// /sencha-core/www/model/TimesheetTask.js
//
// Copyright (C) 2013 ]project-open[
//
// All rights reserved. Please see
// http://www.project-open.com/license/ for details.
/**
A "TimesheetTask" (there also other types of tasks in ]po[)
represents a single Gantt bar in a Gantt diagram. The gantt
bar represents a single project activity or a group of activities.
TimesheetTask is a sub-type of "Project", so it inherits all
fields and characteristics of a project, but not all of them
are actively used.
**/
Ext.define('PO.model.timesheet.TimesheetTask', {
extend: 'Ext.data.Model',
fields: [
// Identity
'id', // The system wide unique ID for this object (-> acs_objects)
'task_id', // The primary key or object_id of the project (-> im_timesheet_tasks)
'project_name', // The name of the task (inherited from Project)
'project_nr', // The short name of the task (inherited from Project)
'company_id', // Customer for whom the task has been created (-> im_companies)
'parent_id', // The parent of the task or NULL for a main project (-> im_projects)
'tree_sortkey', // A strange "bit string" that determines the hierarchical position of the task.
// Contains the same information as "parent_id", maintained automatically by
// triggers in the database
// Main properties of a task
'start_date', // Start of task as ISO timestamp ('2001-01-01 00:00:00+01')
'end_date', // End of task as ISO timestamp ('2099-12-31 00:00:00+01')
{name: 'start_date_date', // Start date in ISO date format ('2001-01-01')
convert: function(value, record) { return record.get('start_date').substring(0,9); }
},
{name: 'end_date_date', convert: function(value, record) { return record.get('end_date').substring(0,9); }},
'percent_completed', // 0 - 100: Defines what has already been done.
'description', // Description of the task activity
'note', // Notes about the task activity
// Advanced properties of a task
'material_id', // The type of activity (-> im_materials)
'uom_id', // Unit or Measure, should nearly always be 320="Hour" (-> im_categories)
'planned_units', // Planned duration of the activity
'billable_units', // Units that can be billed to the customer (company_id)
'cost_center_id', // Optional department/cost center of who executes this activity.
// Only used in specific ]po[ installations (-> im_cost_centers)
'priority', // Priority of the task (-> im_categories)
'sort_order', // Order of the task, with respect to other tasks on the same level
// MS-Project: These fields are used to contain information imported from MS-Project
// This information determines how tasks are scheduled by the task scheduler.
'scheduling_constraint_id', // MS-Project: Type of scheduling constraint (-> im_cost_centers)
'scheduling_constraint_date', // MS-Project: Field for "should not start before" constraint or similar
'effort_driven_p', // MS-Project: Effort driven?
'effort_driven_type_id', // MS-Project: Specific way to to determine effort driven
'deadline_date', // MS-Project: Deadline for this activitiy
// Gantt-Project: This is an open-source clone of MS-Project
'gantt_project_id', // ID of the task when imported from Gantt-project
// Project Billing: These fields are used when using ]po[ to automatically create invoices from tasks.
'invoice_id', // ID of the invoice that contains this task (-> im_invoices)
// Fields inherited from im_projects that don't really make sense for tasks
'project_status_id', // Projects may have many states, but tasks should be either 76=open or 81=closed.
'project_type_id', // Type of the project. This value should be 100=Task always.
'project_lead_id', // Single person responsible for the success of the task.
// This field is used in ]po[ only for "main projects", so this
// should be always NULL for tasks.
'on_track_status_id', // Is the task on-track? Normally not used for tasks. 66=green, 67=yellow, 68=red
'level', // 0 for a main project, 1 for a first level task etc.
// Locking: This is is not supported at the moment (2013-11-26) but might be in the future
'lock_user', // ID of the user who locked the task
'lock_date', // When was the task locked (ISO timestamp)
'lock_ip', // IP address of the user who locked
// Object audit information
'object_type', // This should always be 'im_timesheet_task'.
'creation_date', // When was the task created initially?
'creation_user', // User_id of the guy who creating the task
'creation_ip', // IP address of the user who created the task
'last_modified', // When was the task last modified?
'modifying_user', // Who modified the task?
'modifying_ip', // IP address of the last modification
// Dereferenced fields contain pretty names (English) for the corresponding *_id fields.
// These fields only have a value if you have specified the parameter deref_p=1 in
// the REST interface URL
'project_status_id_deref', // Project Status ("Open" or "Closed")
'project_type_id_deref', // Project Type (always "Task")
'project_priority_id_deref', // Project Priority
'company_id_deref', // Customer name
'parent_id_deref', // Name of parent project or task
'project_lead_id_deref', // Project manager name
'material_id_deref', // Name of material (service type)
'uom_id_deref', // Unit of measure (should alsways be "Hour")
'on_track_status_id_deref', // Is the task on-track? "Green", "Yellow" or "Red"
{ name: 'indent', // A &nbsp; sequence representing the project indentation
convert: function(value, record) {
var level = record.get('level');
var result = '';
while (level > 0) {
result = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' + result;
level = level - 1;
}
return result;
}
}
],
proxy: {
type: 'rest',
url: '/intranet-rest/im_timesheet_task',
appendId: true, // Append the object_id: ../im_ticket/<object_id>
timeout: 300000,
extraParams: {
format: 'json', // Tell the ]po[ REST to return JSON data.
deref_p: '1'
},
reader: {
type: 'json', // Tell the Proxy Reader to parse JSON
root: 'data', // Where do the data start in the JSON file?
totalProperty: 'total' // Total number of tickets for pagination
},
writer: {
type: 'json' // Allow Sencha to write ticket changes
}
}
});
// /sencha-core/www/store/timesheet/TimesheetTask.js
//
// Copyright (C) 2013 ]project-open[
//
// All rights reserved. Please see
// http://www.project-open.com/license/ for details.
/*
Ext.define('PO.store.timesheet.TaskStatusStore', {
extend: 'Ext.data.Store',
storeId: 'taskStatusStore',
fields: ['id', 'category'],
data: [
{"id":"76", "category":"Open"},
{"id":"81", "category":"Closed"}
]
});
*/
Ext.define('PO.store.timesheet.TaskStatusStore', {
extend: 'Ext.data.Store',
storeId: 'taskStatusStore',
autoLoad: true,
requires: ['PO.model.category.Category'],
model: 'PO.model.category.Category',
pageSize: 1000,
proxy: {
type: 'rest',
url: '/intranet-rest/im_category',
appendId: true,
extraParams: {
format: 'json',
category_type: '\'Intranet Project Status\''
},
reader: { type: 'json', root: 'data' }
},
sorters: [{
property: 'category_translated',
direction: 'ASC'
}]
});
// /sencha-core/www/store/timesheet/TimesheetTask.js
//
// Copyright (C) 2013 ]project-open[
//
// All rights reserved. Please see
// http://www.project-open.com/license/ for details.
/*
Ext.define('PO.store.timesheet.TaskStatusStore', {
extend: 'Ext.data.Store',
storeId: 'taskStatusStore',
fields: ['id', 'category'],
data: [
{"id":"76", "category":"Open"},
{"id":"81", "category":"Closed"}
]
});
*/
Ext.define('PO.store.timesheet.TaskStatusStore', {
extend: 'PO.class.CategoryStore',
model: 'PO.model.category.Category',
storeId: 'taskStatusStore',
autoLoad: true,
remoteFilter: true,
pageSize: 1000,
proxy: {
type: 'rest',
url: '/intranet-rest/im_category',
appendId: true,
extraParams: {
format: 'json',
category_type: '\'Intranet Project Status\''
},
reader: { type: 'json', root: 'data' }
}
});
// /sencha-core/www/store/timesheet/TaskTreeStore.js
//
// Copyright (C) 2013 ]project-open[
//
// All rights reserved. Please see
// http://www.project-open.com/license/ for details.
Ext.define('PO.store.timesheet.TaskTreeStore', {
extend: 'Ext.data.TreeStore',
storeId: 'taskTreeStore',
model: 'PO.model.timesheet.TimesheetTask',
autoload: false,
autoSync: true,
folderSort: true,
proxy: {
type: 'ajax',
url: '/sencha-task-editor/treegrid.json',
extraParams: {
project_id: 0 // The application needs to replace this by the actual
// project_id of the project before calling load()
},
api: {
create : '/sencha-task-editor/treegrid.json?create=1',
read : '/sencha-task-editor/treegrid.json?read=1',
update : '/sencha-task-editor/treegrid-update',
destroy : '/sencha-task-editor/treegrid.json?destroy=1',
},
reader: {
type: 'json',
rootProperty: 'data'
},
writer: {
type: 'json',
rootProperty: 'data'
}
}
});
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