erp5_web_project_ui: new front page
/*jslint nomen: true, indent: 2 */ | ||
/*global window, rJS, RSVP, document, SimpleQuery, ComplexQuery, Query, parseInt, jIO, URL */ | ||
(function (window, rJS, RSVP, document, SimpleQuery, ComplexQuery, Query, parseInt, jIO, URL) { | ||
"use strict"; | ||
var STATUS_OK = "green", | ||
STATUS_NOT_OK = "red", | ||
NONE_STATUS = "none", | ||
RADIX = 10, | ||
STATUS_SPAN = "status", | ||
TOTAL_SPAN = "total", | ||
OUTDATED_SPAN = "outdated", | ||
NUMBER_SPAN = "number", | ||
NAME_SPAN = "name", | ||
FORUM_LINK_ID_SUFFIX = "forum", | ||
FORUM_LINK_TYPE = "link", | ||
OUTDATED_LABEL = " out of date", | ||
FAILED_LABEL = " failed", | ||
TEST_RESULT_PORTAL_TYPE = "Test Result", | ||
QUERY_LIMIT = 100000, | ||
SUPERVISOR_FIELD_TITLE = "Supervisor", | ||
//XXX hardcoded limit dates (3 months for milestones, 3 weeks for documents) | ||
//define dates in System Preference Project tab? | ||
//date ISO string format: "yyyy-mm-ddThh:mm:ss.mmmm" | ||
//JIO query date format: "yyyy-mm-dd hh:mm:ss" | ||
MILESTONE_LIMIT_DATE = new Date(new Date().setDate(new Date().getDate() - 90)) | ||
.toISOString().substring(0, new Date().toISOString().length - 5).replace("T", " "), | ||
DOCUMENT_LIMIT_DATE = new Date(new Date().setDate(new Date().getDate() - 21)) | ||
.toISOString().substring(0, new Date().toISOString().length - 5).replace("T", " "), | ||
PORTAL_TITLE_DICT = {"Task": "Tasks", | ||
"Test Result" : "Test Results", | ||
"Bug" : "Bugs", | ||
"Project Milestone" : "Milestones", | ||
"Task Report": "Task Reports"}, | ||
PORTAL_TYPE_LIST = ["Task", "Bug", "Task Report"], | ||
VALID_STATE_LIST = ["planned", "auto_planned", "ordered", "confirmed", | ||
"ready", "stopped", "started", "submitted", "validated"]; | ||
function createMultipleSimpleOrQuery(key, value_list) { | ||
var i, | ||
query_list = []; | ||
for (i = 0; i < value_list.length; i += 1) { | ||
query_list.push(new SimpleQuery({ | ||
key: key, | ||
operator: "", | ||
type: "simple", | ||
value: value_list[i] | ||
})); | ||
} | ||
return new ComplexQuery({ | ||
operator: "OR", | ||
query_list: query_list, | ||
type: "complex" | ||
}); | ||
} | ||
function getProjectId(id) { | ||
var segments = id.split("/"); | ||
if (segments.length === 2) { | ||
return id; | ||
} | ||
return segments.slice(0, 2).join("/"); | ||
} | ||
function getProjectHtlmElementId(project_id, type, suffix, hash_selector) { | ||
hash_selector = hash_selector ? '#' : ''; | ||
//remove not allowed html id chars (spaces, slashes) | ||
return hash_selector + [project_id, type, suffix].join("-") | ||
.replace(/\//g, "-").replace(/\s/g, "-"); | ||
} | ||
function getComplexQuery(query_dict, operator, extra_query) { | ||
var key, | ||
query_list = []; | ||
for (key in query_dict) { | ||
if (query_dict.hasOwnProperty(key)) { | ||
query_list.push(new SimpleQuery({ | ||
key: key, | ||
operator: "", | ||
type: "simple", | ||
value: query_dict[key] | ||
})); | ||
} | ||
} | ||
if (extra_query) { | ||
query_list.push(extra_query); | ||
} | ||
return new ComplexQuery({ | ||
operator: operator, | ||
query_list: query_list, | ||
type: "complex" | ||
}); | ||
} | ||
function renderProjectLine(project_id, portal_type, total_count, outdated_count) { | ||
var total_span = document.querySelector( | ||
getProjectHtlmElementId(project_id, portal_type, TOTAL_SPAN, true) | ||
), | ||
outdated_span = document.querySelector( | ||
getProjectHtlmElementId(project_id, portal_type, OUTDATED_SPAN, true) | ||
), | ||
status_span = document.querySelector( | ||
getProjectHtlmElementId(project_id, portal_type, STATUS_SPAN, true) | ||
), | ||
number_span = document.querySelector( | ||
getProjectHtlmElementId(project_id, portal_type, NUMBER_SPAN, true) | ||
); | ||
if (total_count > 0 && total_span) { | ||
total_span.textContent = parseInt(total_span.textContent, RADIX) + total_count; | ||
} | ||
if (outdated_span) { | ||
outdated_span.textContent = parseInt(outdated_span.textContent, RADIX) + | ||
outdated_count; | ||
} | ||
if (status_span) { | ||
if (outdated_count > 0) { | ||
status_span.classList.remove(STATUS_OK); | ||
status_span.classList.add(STATUS_NOT_OK); | ||
} else if (!status_span.classList.value.includes(STATUS_NOT_OK)) { | ||
status_span.classList.add(STATUS_OK); | ||
} | ||
} | ||
if (number_span) { | ||
if (outdated_count > 0) { | ||
number_span.classList.remove("ui-hidden"); | ||
number_span.classList.add("ui-visible"); | ||
} | ||
} | ||
} | ||
function renderProjectDocumentLines(gadget, limit_date) { | ||
var i, | ||
query_list = [], | ||
document_list = [], | ||
document_query; | ||
query_list.push(new SimpleQuery({ | ||
key: "source_project__validation_state", | ||
operator: "=", | ||
type: "simple", | ||
value: "validated" | ||
})); | ||
query_list.push(createMultipleSimpleOrQuery('portal_type', PORTAL_TYPE_LIST)); | ||
query_list.push(createMultipleSimpleOrQuery('simulation_state', VALID_STATE_LIST)); | ||
if (limit_date) { | ||
query_list.push(new SimpleQuery({ | ||
key: "modification_date", | ||
operator: "<", | ||
type: "simple", | ||
value: limit_date | ||
})); | ||
} | ||
document_query = new ComplexQuery({ | ||
operator: "AND", | ||
query_list: query_list, | ||
type: "complex" | ||
}); | ||
return gadget.jio_allDocs({ | ||
query: Query.objectToSearchText(document_query), | ||
limit: QUERY_LIMIT, | ||
select_list: ['source_project__relative_url', 'portal_type', 'count(*)'], | ||
group_by: ['portal_type', 'source_project__relative_url'], | ||
sort_on: [["modification_date", "descending"]] | ||
}) | ||
.push(function (result) { | ||
document_list = result.data.rows; | ||
for (i = 0; i < document_list.length; i += 1) { | ||
renderProjectLine(getProjectId(document_list[i].value | ||
.source_project__relative_url), | ||
document_list[i].value.portal_type, | ||
limit_date ? 0 : document_list[i].value["count(*)"], | ||
limit_date ? document_list[i].value["count(*)"] : 0); | ||
} | ||
}); | ||
} | ||
function renderMilestoneLines(gadget, limit_date) { | ||
|
||
var i, | ||
query_list = [], | ||
milestone_list, | ||
milestone_query = getComplexQuery({"portal_type" : "Project Milestone", | ||
"validation_state" : "validated"}, | ||
"AND"); | ||
if (limit_date) { | ||
query_list.push(milestone_query); | ||
query_list.push(new SimpleQuery({ | ||
key: "modification_date", | ||
operator: "<", | ||
type: "simple", | ||
value: limit_date | ||
})); | ||
milestone_query = new ComplexQuery({ | ||
operator: "AND", | ||
query_list: query_list, | ||
type: "complex" | ||
}); | ||
} | ||
return new RSVP.Queue() | ||
|
||
.push(function () { | ||
return gadget.jio_allDocs({ | ||
query: Query.objectToSearchText(milestone_query), | ||
limit: QUERY_LIMIT, | ||
select_list: ['title', 'portal_type', 'count(*)'], | ||
group_by: ['parent_uid'], | ||
sort_on: [["modification_date", "descending"]] | ||
}); | ||
}) | ||
.push(function (result) { | ||
milestone_list = result.data.rows; | ||
for (i = 0; i < milestone_list.length; i += 1) { | ||
renderProjectLine(getProjectId(milestone_list[i].id), | ||
milestone_list[i].value.portal_type, | ||
limit_date ? 0 : milestone_list[i].value["count(*)"], | ||
limit_date ? milestone_list[i].value["count(*)"] : 0); | ||
} | ||
}); | ||
} | ||
function getProjectList(gadget) { | ||
var project_query = Query.objectToSearchText( | ||
getComplexQuery({"portal_type" : "Project", | ||
"validation_state" : "validated"}, | ||
"AND") | ||
); | ||
return gadget.jio_allDocs({ | ||
query: project_query, | ||
limit: QUERY_LIMIT, | ||
select_list: ['title', 'source_decision_title', 'source_decision_relative_url'], | ||
sort_on: [["title", "ascending"]] | ||
}) | ||
.push(function (result) { | ||
return result.data.rows; | ||
}); | ||
} | ||
function getUrlParameterDict(jio_key, view, sort_list, column_list, extended_search) { | ||
return { | ||
command: 'push_history', | ||
options: { | ||
'jio_key': jio_key, | ||
'page': 'form', | ||
'view': view, | ||
'field_listbox_sort_list:json': sort_list, | ||
'field_listbox_column_list:json': column_list, | ||
'extended_search': extended_search | ||
} | ||
}; | ||
} | ||
function createProjectQuery(project_jio_key, key_value_list) { | ||
var i, query_list = [], id_query_list = [], id_complex_query; | ||
if (project_jio_key) { | ||
//relation to project or child project lines | ||
id_query_list.push(new SimpleQuery({ | ||
key: "source_project__relative_url", | ||
operator: "", | ||
type: "simple", | ||
value: project_jio_key | ||
})); | ||
id_query_list.push(new SimpleQuery({ | ||
key: "source_project__relative_url", | ||
operator: "", | ||
type: "simple", | ||
value: project_jio_key + "/%%" | ||
})); | ||
id_complex_query = new ComplexQuery({ | ||
operator: "OR", | ||
query_list: id_query_list, | ||
type: "complex" | ||
}); | ||
query_list.push(id_complex_query); | ||
} | ||
for (i = 0; i < key_value_list.length; i += 1) { | ||
query_list.push(new SimpleQuery({ | ||
key: key_value_list[i][0], | ||
operator: "", | ||
type: "simple", | ||
value: key_value_list[i][1] | ||
})); | ||
} | ||
return Query.objectToSearchText(new ComplexQuery({ | ||
operator: "AND", | ||
query_list: query_list, | ||
type: "complex" | ||
})); | ||
} | ||
function renderProjectList(gadget, project_list) { | ||
var i, | ||
project_html, | ||
left_div_html, | ||
project_html_element_list, | ||
left_line_html, | ||
ul_list = document.querySelector("#js-project-list"), | ||
spinner = document.querySelector("#js-spinner"), | ||
url_parameter_list = [], | ||
milestone_url_list = [], | ||
task_url_list = [], | ||
task_report_url_list = [], | ||
bug_url_list = [], | ||
test_result_url_list = [], | ||
supervisor_url_list = [], | ||
milestone_view, | ||
project_view; | ||
function createProjectHtmlElement(project_id, project_title, | ||
project_url, supervisor, supervisor_url) { | ||
var project_li = document.createElement('li'), | ||
box_div = document.createElement('div'), | ||
title_div = document.createElement('div'), | ||
info_div = document.createElement('div'), | ||
left_info_div = document.createElement('div'), | ||
right_div = document.createElement('div'), | ||
right_line_div = document.createElement('div'), | ||
supervisor_field_div = document.createElement('div'), | ||
supervisor_value_div = document.createElement('div'), | ||
project_link = document.createElement('a'), | ||
forum_link = document.createElement('a'), | ||
supervisor_field_label = document.createElement('label'), | ||
supervisor_value_link = document.createElement('a'); | ||
if (supervisor) { | ||
supervisor_field_div.classList.add("field", "project-line"); | ||
supervisor_value_div.classList.add("field", "project-line", "value"); | ||
supervisor_field_label.innerHTML = SUPERVISOR_FIELD_TITLE; | ||
supervisor_value_link.innerHTML = supervisor; | ||
supervisor_value_link.href = supervisor_url; | ||
supervisor_field_div.appendChild(supervisor_field_label); | ||
supervisor_value_div.appendChild(supervisor_value_link); | ||
right_div.appendChild(supervisor_field_div); | ||
right_div.appendChild(supervisor_value_div); | ||
} | ||
box_div.classList.add("project-box"); | ||
title_div.classList.add("project-title"); | ||
project_link.href = project_url; | ||
project_link.innerHTML = project_title; | ||
title_div.appendChild(project_link); | ||
info_div.classList.add("project-info"); | ||
left_info_div.classList.add("project-left"); | ||
right_div.classList.add("project-right"); | ||
right_line_div.classList.add("project-line"); | ||
forum_link.setAttribute("id", getProjectHtlmElementId(project_id, FORUM_LINK_TYPE, | ||
FORUM_LINK_ID_SUFFIX)); | ||
forum_link.classList.add("ui-hidden"); | ||
right_line_div.appendChild(forum_link); | ||
right_div.appendChild(right_line_div); | ||
info_div.appendChild(left_info_div); | ||
info_div.appendChild(right_div); | ||
box_div.appendChild(title_div); | ||
box_div.appendChild(info_div); | ||
project_li.appendChild(box_div); | ||
return [project_li, left_info_div]; | ||
} | ||
function createProjectLineHtmlElement(project_id, portal_type, line_url, title, | ||
total_count, out_count, status_color) { | ||
var line_div = document.createElement('div'), | ||
status_span = document.createElement('span'), | ||
name_span = document.createElement('span'), | ||
number_span = document.createElement('span'), | ||
outdated_span = document.createElement('span'), | ||
total_span = document.createElement('span'), | ||
open_bracket_span = document.createElement('span'), | ||
close_bracket_span = document.createElement('span'), | ||
outdated_label_span = document.createElement('span'), | ||
line_link = document.createElement('a'); | ||
line_div.classList.add("project-line"); | ||
status_span.classList.add(STATUS_SPAN); | ||
status_span.classList.add(status_color); | ||
status_span.classList.add("margined"); | ||
status_span.setAttribute("id", getProjectHtlmElementId(project_id, | ||
portal_type, STATUS_SPAN)); | ||
total_span.classList.add("margined"); | ||
total_span.innerHTML = total_count; | ||
total_span.setAttribute("id", getProjectHtlmElementId(project_id, | ||
portal_type, TOTAL_SPAN)); | ||
name_span.classList.add("name"); | ||
name_span.classList.add("margined"); | ||
name_span.innerHTML = title; | ||
name_span.setAttribute("id", getProjectHtlmElementId(project_id, | ||
portal_type, NAME_SPAN)); | ||
outdated_span.innerHTML = out_count; | ||
outdated_span.setAttribute("id", getProjectHtlmElementId(project_id, | ||
portal_type, OUTDATED_SPAN)); | ||
open_bracket_span.innerHTML = "("; | ||
outdated_label_span.innerHTML = (portal_type === TEST_RESULT_PORTAL_TYPE) ? FAILED_LABEL : OUTDATED_LABEL; | ||
close_bracket_span.innerHTML = ")"; | ||
number_span.appendChild(open_bracket_span); | ||
number_span.appendChild(outdated_span); | ||
number_span.appendChild(outdated_label_span); | ||
number_span.appendChild(close_bracket_span); | ||
number_span.setAttribute("id", getProjectHtlmElementId(project_id, | ||
portal_type, NUMBER_SPAN)); | ||
number_span.classList.add("ui-hidden"); | ||
line_div.appendChild(status_span); | ||
line_div.appendChild(total_span); | ||
line_div.appendChild(name_span); | ||
line_div.appendChild(number_span); | ||
line_link.appendChild(line_div); | ||
|
||
if (line_url) { | ||
line_link.href = line_url; | ||
} | ||
return line_link; | ||
} | ||
return gadget.getSetting("hateoas_url") | ||
.push(function (hateoas_url) { | ||
for (i = 0; i < project_list.length; i += 1) { | ||
milestone_view = hateoas_url + | ||
'/ERP5Document_getHateoas?mode=traverse&relative_url=' + | ||
project_list[i].id + '&view=Project_viewMilestoneList'; | ||
project_view = hateoas_url + | ||
'/ERP5Document_getHateoas?mode=traverse&relative_url=' + | ||
project_list[i].id + | ||
'&view=Project_viewQuickOverview'; | ||
url_parameter_list.push( | ||
getUrlParameterDict(project_list[i].id, | ||
project_view) | ||
); | ||
milestone_url_list.push( | ||
getUrlParameterDict('milestone_module', | ||
milestone_view, | ||
[["stop_date", "ascending"]], | ||
null, | ||
createProjectQuery(null, | ||
[["selection_domain_date_milestone_domain", "future"]])) | ||
); | ||
task_url_list.push( | ||
getUrlParameterDict('task_module', | ||
"view", | ||
[["delivery.start_date", "descending"]], | ||
["title", "delivery.start_date", "source_title", "translated_simulation_state_title"], | ||
createProjectQuery(project_list[i].id, | ||
[["selection_domain_state_task_domain", "opened"]])) | ||
); | ||
task_report_url_list.push( | ||
getUrlParameterDict('task_report_module', | ||
'view', | ||
[["delivery.start_date", "descending"]], | ||
["title", "delivery.start_date", "source_title", "translated_simulation_state_title"], | ||
createProjectQuery(project_list[i].id, | ||
[["selection_domain_state_task_report_domain", "confirmed"]])) | ||
); | ||
bug_url_list.push( | ||
getUrlParameterDict('bug_module', | ||
"view", | ||
[["delivery.start_date", "descending"]], | ||
["title", "description", "source_person_title", "destination_person_title", | ||
"delivery.start_date", "translated_simulation_state_title"], | ||
createProjectQuery(project_list[i].id, | ||
[["selection_domain_state_bug_domain", "open"]])) | ||
); | ||
test_result_url_list.push( | ||
getUrlParameterDict('test_result_module', | ||
'view', | ||
[["delivery.start_date", "descending"]], | ||
null, | ||
createProjectQuery(project_list[i].id, [])) | ||
); | ||
supervisor_url_list.push( | ||
getUrlParameterDict(project_list[i].value.source_decision_relative_url, | ||
'view') | ||
); | ||
} | ||
return RSVP.all([gadget.getUrlForList(url_parameter_list), | ||
gadget.getUrlForList(milestone_url_list), | ||
gadget.getUrlForList(task_url_list), | ||
gadget.getUrlForList(task_report_url_list), | ||
gadget.getUrlForList(bug_url_list), | ||
gadget.getUrlForList(test_result_url_list), | ||
gadget.getUrlForList(supervisor_url_list)]); | ||
}) | ||
.push(function (result_list) { | ||
var type, | ||
line_url; | ||
spinner.classList.add("ui-hidden"); | ||
for (i = 0; i < project_list.length; i += 1) { | ||
project_html_element_list = | ||
createProjectHtmlElement(project_list[i].id, | ||
project_list[i].value.title, | ||
result_list[0][i], | ||
project_list[i].value.source_decision_title, | ||
result_list[6][i]); | ||
project_html = project_html_element_list[0]; | ||
left_div_html = project_html_element_list[1]; | ||
for (type in PORTAL_TITLE_DICT) { | ||
if (PORTAL_TITLE_DICT.hasOwnProperty(type)) { | ||
line_url = (function (portal_type) { | ||
switch (portal_type) { | ||
case 'Project Milestone': | ||
return result_list[1][i]; | ||
case 'Task': | ||
return result_list[2][i]; | ||
case 'Task Report': | ||
return result_list[3][i]; | ||
case 'Bug': | ||
return result_list[4][i]; | ||
case 'Test Result': | ||
return result_list[5][i]; | ||
} | ||
})(type); | ||
left_line_html = createProjectLineHtmlElement(project_list[i].id, type, | ||
line_url, | ||
((PORTAL_TITLE_DICT | ||
.hasOwnProperty(type)) ? | ||
PORTAL_TITLE_DICT[type] : | ||
type), | ||
0, 0, NONE_STATUS); | ||
left_div_html.appendChild(left_line_html); | ||
} | ||
} | ||
ul_list.appendChild(project_html); | ||
} | ||
}); | ||
} | ||
rJS(window) | ||
///////////////////////////////////////////////////////////////// | ||
// Acquired methods | ||
///////////////////////////////////////////////////////////////// | ||
.declareAcquiredMethod("updateHeader", "updateHeader") | ||
.declareAcquiredMethod("getUrlForList", "getUrlForList") | ||
.declareAcquiredMethod("jio_allDocs", "jio_allDocs") | ||
.declareAcquiredMethod("getSetting", "getSetting") | ||
.declareMethod('render', function (options) { | ||
var gadget = this; | ||
return getProjectList(gadget) | ||
.push(function (project_list) { | ||
options.project_list = project_list; | ||
return gadget.changeState(options); | ||
}); | ||
}) | ||
.onStateChange(function () { | ||
var gadget = this; | ||
return gadget.updateHeader({ | ||
page_title: 'Project Management' | ||
}); | ||
}) | ||
.declareService(function () { | ||
var gadget = this; | ||
return renderProjectList(gadget, gadget.state.project_list) | ||
.push(function () { | ||
//run the rest of queries and render async | ||
gadget.renderMilestoneInfo(); | ||
gadget.renderOutdatedMilestoneInfo(); | ||
gadget.renderProjectDocumentInfo(); | ||
gadget.renderOutdatedDocumentInfo(); | ||
gadget.renderTestResultInfo(); | ||
gadget.renderProjectForumLink(); | ||
}); | ||
}) | ||
.declareJob("renderMilestoneInfo", function () { | ||
|
||
return renderMilestoneLines(this); | ||
}) | ||
.declareJob("renderOutdatedMilestoneInfo", function () { | ||
return renderMilestoneLines(this, MILESTONE_LIMIT_DATE); | ||
}) | ||
.declareJob("renderProjectDocumentInfo", function () { | ||
return renderProjectDocumentLines(this); | ||
}) | ||
.declareJob("renderOutdatedDocumentInfo", function () { | ||
return renderProjectDocumentLines(this, DOCUMENT_LIMIT_DATE); | ||
}) | ||
.declareJob("renderTestResultInfo", function () { | ||
return new RSVP.Queue() | ||
.push(function () { | ||
return jIO.util.ajax({ | ||
type: "GET", | ||
url: new URL('./ERP5Site_getProjectTestStatusData', window.location.href) | ||
}); | ||
}) | ||
.push(function (result) { | ||
var project_id, | ||
project_test_status_dict; | ||
project_test_status_dict = JSON.parse(result.target.response); | ||
for (project_id in project_test_status_dict) { | ||
if (project_test_status_dict.hasOwnProperty(project_id)) { | ||
renderProjectLine(project_id, | ||
TEST_RESULT_PORTAL_TYPE, | ||
parseInt(project_test_status_dict[project_id].all_tests, RADIX), | ||
parseInt(project_test_status_dict[project_id].failures, RADIX)); | ||
} | ||
} | ||
}); | ||
}) | ||
.declareJob("renderProjectForumLink", function () { | ||
var gadget = this, | ||
i, | ||
forum_link_html, | ||
forum_link_list, | ||
link_query = getComplexQuery({"portal_type" : "Link", | ||
"validation_state" : "reachable", | ||
"relative_url" : "project_module/%/forum_link"}, | ||
"AND"); | ||
return new RSVP.Queue() | ||
.push(function () { | ||
return gadget.jio_allDocs({ | ||
query: Query.objectToSearchText(link_query), | ||
limit: QUERY_LIMIT, | ||
select_list: ['url_string'], | ||
sort_on: [["modification_date", "descending"]] | ||
}); | ||
}) | ||
.push(function (result) { | ||
forum_link_list = result.data.rows; | ||
for (i = 0; i < forum_link_list.length; i += 1) { | ||
forum_link_html = document.querySelector( | ||
getProjectHtlmElementId(getProjectId(forum_link_list[i].id), | ||
FORUM_LINK_TYPE, | ||
FORUM_LINK_ID_SUFFIX, true) | ||
); | ||
if (forum_link_html) { | ||
forum_link_html.href = forum_link_list[i].value.url_string; | ||
forum_link_html.innerHTML = "Project Forum"; | ||
forum_link_html.classList.remove("ui-hidden"); | ||
} | ||
} | ||
}); | ||
}) | ||
.declareMethod('getContent', function () { | ||
return {}; | ||
}) | ||
.declareMethod('checkValidity', function () { | ||
return true; | ||
}); | ||
}(window, rJS, RSVP, document, SimpleQuery, ComplexQuery, Query, parseInt, jIO, URL)); |
erp5_forge | ||
|
||
erp5_project | ||
erp5_web_renderjs_ui | ||
\ No newline at end of file |