Commit 075f68fc authored by Romain Courteaud's avatar Romain Courteaud

[erp5_web_bug_tracker] WIP

parent 03a50d16
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>Jio Gadget</title>
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="jiodev.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_erp5_bug_tracker_jio.js" type="text/javascript"></script>
</head>
<body>
<div data-gadget-url='gadget_jio.html' data-gadget-scope='jio'></div>
</body>
</html>
\ No newline at end of file
/*global window, rJS, RSVP, UriTemplate, URI, Query, SimpleQuery, ComplexQuery, jIO */
/*jslint indent: 2, maxerr: 3, nomen: true */
(function (window, rJS, RSVP, UriTemplate) {
"use strict";
function wrapJioCall(gadget, method_name, argument_list) {
var storage = gadget.state_parameter_dict.jio_storage,
regexp = /^X-Delegate uri="(http[s]*:\/\/[\/\-\[\]{}()*+:?.,\\\^$|#\s\w%]+)"$/,
login_page;
return storage[method_name].apply(storage, argument_list)
.push(undefined, function (error) {
if ((error.target !== undefined) && (error.target.status === 401)) {
login_page = error.target.getResponseHeader('WWW-Authenticate');
// Only connect to https to login
if (regexp.test(login_page)) {
return gadget.getUrlFor({
command: 'login',
absolute_url: true
})
.push(function (came_from) {
return gadget.redirect({
command: 'raw',
options: {
url: UriTemplate.parse(regexp.exec(login_page)[1]).expand({came_from: came_from})
}
});
});
/*
window.location = UriTemplate.parse(
regexp.exec(login_page)[1]
).expand({came_from: window.location.href + "{&me}"});
return RSVP.timeout(5000);
*/
// Redirect to the login view
}
// return gadget.redirect({command: 'display', options: {page: 'login'}});
}
throw error;
});
}
/*
function isSingleLocalRoles(parsed_query) {
if ((parsed_query instanceof SimpleQuery) &&
(parsed_query.key === 'local_roles')) {
// local_roles:"Assignee"
return parsed_query.value;
}
}
function isMultipleLocalRoles(parsed_query) {
var i,
sub_query,
is_multiple = true,
local_role_list = [];
if ((parsed_query instanceof ComplexQuery) &&
(parsed_query.operator === 'OR')) {
for (i = 0; i < parsed_query.query_list.length; i += 1) {
sub_query = parsed_query.query_list[i];
if ((sub_query instanceof SimpleQuery) &&
(sub_query.key === 'local_roles')) {
local_role_list.push(sub_query.value);
} else {
is_multiple = false;
}
}
if (is_multiple) {
// local_roles:"Assignee" OR local_roles:"Assignor"
return local_role_list;
}
}
}
*/
rJS(window)
.ready(function (gadget) {
return gadget.getDeclaredGadget('jio')
.push(function (jio_gadget) {
// Initialize the gadget local parameters
gadget.state_parameter_dict = {jio_storage: jio_gadget};
});
})
.declareAcquiredMethod('getSetting', 'getSetting')
.declareAcquiredMethod('redirect', 'redirect')
.declareAcquiredMethod('getUrlFor', 'getUrlFor')
.declareMethod('createJio', function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
gadget.getSetting('hateoas_url'),
gadget.getSetting('default_view_reference')
]);
})
/*
.push(function (setting_list) {
return gadget.state_parameter_dict.jio_storage.createJio({
type: "erp5",
url: setting_list[0],
default_view_reference: setting_list[1]
});
});
*/
.push(function (setting_list) {
return gadget.state_parameter_dict.jio_storage.createJio({
type: "replicate",
query: {
query: 'portal_type:"Bug" OR portal_type:"Bug Module"',
limit: [0, 1234567890]
},
use_remote_post: true,
conflict_handling: 2,
check_local_modification: false,
check_local_creation: false,
check_local_deletion: false,
check_remote_modification: false,
check_remote_creation: true,
check_remote_deletion: true,
local_sub_storage: {
type: "query",
sub_storage: {
type: "uuid",
sub_storage: {
type: "indexeddb",
database: "bug-tracker-erp5"
}
}
},
remote_sub_storage: {
type: "erp5",
url: setting_list[0],
default_view_reference: setting_list[1]
}
});
})
.push(function () {
if (navigator.onLine) {
return wrapJioCall(gadget, 'repair', []);
}
// return gadget.repairAndDelay();
});
})
.declareMethod('createJioXXX', function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
gadget.getSetting('hateoas_url'),
gadget.getSetting('default_view_reference')
]);
})
.push(function (setting_list) {
return gadget.state_parameter_dict.jio_storage.createJio({
type: "erp5",
url: setting_list[0],
default_view_reference: setting_list[1]
});
});
})
/*
.declareMethod('allDocs', function (option_dict) {
// throw new Error('do not use all docs');
if (option_dict.list_method_template === undefined) {
return wrapJioCall(this, 'allDocs', arguments);
}
var query = option_dict.query,
i,
parsed_query,
sub_query,
result_list,
tmp_list = [],
local_roles;
if (option_dict.query) {
parsed_query = jIO.QueryFactory.create(option_dict.query);
result_list = isSingleLocalRoles(parsed_query);
if (result_list) {
query = undefined;
local_roles = result_list;
} else {
result_list = isMultipleLocalRoles(parsed_query);
if (result_list) {
query = undefined;
local_roles = result_list;
} else if ((parsed_query instanceof ComplexQuery) &&
(parsed_query.operator === 'AND')) {
// portal_type:"Person" AND local_roles:"Assignee"
for (i = 0; i < parsed_query.query_list.length; i += 1) {
sub_query = parsed_query.query_list[i];
result_list = isSingleLocalRoles(sub_query);
if (result_list) {
local_roles = result_list;
parsed_query.query_list.splice(i, 1);
query = Query.objectToSearchText(parsed_query);
i = parsed_query.query_list.length;
} else {
result_list = isMultipleLocalRoles(sub_query);
if (result_list) {
local_roles = result_list;
parsed_query.query_list.splice(i, 1);
query = Query.objectToSearchText(parsed_query);
i = parsed_query.query_list.length;
}
}
}
}
}
option_dict.query = query;
option_dict.local_roles = local_roles;
}
if (option_dict.sort_on) {
for (i = 0; i < option_dict.sort_on.length; i += 1) {
tmp_list.push(JSON.stringify(option_dict.sort_on[i]));
}
option_dict.sort_on = tmp_list;
}
return wrapJioCall(
this,
'getAttachment',
[
// XXX Ugly hardcoded meaningless id...
"erp5",
new UriTemplate.parse(option_dict.list_method_template)
.expand(option_dict),
{format: "json"}
]
)
.push(function (catalog_json) {
var data = catalog_json._embedded.contents,
count = data.length,
k,
uri,
item,
result = [];
for (k = 0; k < count; k += 1) {
item = data[k];
uri = new URI(item._links.self.href);
delete item._links;
result.push({
id: uri.segment(2),
doc: {},
value: item
});
}
return {
data: {
rows: result,
total_rows: result.length
}
};
});
})
*/
.declareMethod('allDocs', function (options) {
return wrapJioCall(this, 'allDocs', [options]);
})
.declareMethod('get', function (id) {
return wrapJioCall(this, 'get', [id]);
})
.declareJob('delayRepair', function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return RSVP.delay(10000);
})
.push(function () {
return gadget.repairAndDelay();
});
})
.declareJob('repairAndDelay', function () {
var gadget = this;
return wrapJioCall(this, 'repair', []);
/*
.push(function () {
return gadget.delayRepair();
});
*/
});
/*
.declareMethod('getAttachment', function (id, name) {
return wrapJioCall(this, 'getAttachment', [id, name, {format: "json"}]);
})
.declareMethod('putAttachment', function (id, name, json) {
return wrapJioCall(this, 'putAttachment', [id, name, JSON.stringify(json)]);
})
.declareMethod('put', function (key, doc) {
return wrapJioCall(this, 'put', [key, doc]);
})
.declareMethod('post', function (doc) {
return wrapJioCall(this, 'post', [doc]);
});
*/
}(window, rJS, RSVP, UriTemplate));
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>ERP5 Page Document</title>
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_erp5_page_bug_tracker_form.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
\ No newline at end of file
/*global document, window, rJS */
/*jslint nomen: true, indent: 2, maxerr: 3 */
(function (document, window, rJS) {
"use strict";
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("jio_get", "jio_get")
.declareAcquiredMethod("redirect", "redirect")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.allowPublicAcquisition('notifySubmit', function () {
return this.triggerSubmit();
})
.declareMethod('triggerSubmit', function () {
return this.getDeclaredGadget('fg')
.push(function (g) {
return g.triggerSubmit();
});
})
.declareMethod("render", function (options) {
var gadget = this,
child_gadget_url;
return gadget.jio_get(options.jio_key)
.push(function (result) {
if (result.portal_type === 'Bug Module') {
child_gadget_url = 'gadget_erp5_bug_tracker_view_bug_module.html';
} else if (result.portal_type === 'Bug') {
child_gadget_url = 'gadget_erp5_bug_tracker_view_bug.html';
} else {
throw new Error('Can not display document: ' + options.jio_key);
}
return gadget.changeState({
jio_key: options.jio_key,
doc: result,
child_gadget_url: child_gadget_url
});
});
})
.onStateChange(function () {
var fragment = document.createElement('div'),
gadget = this;
// Clear first to DOM, append after to reduce flickering/manip
while (this.element.firstChild) {
this.element.removeChild(this.element.firstChild);
}
this.element.appendChild(fragment);
return gadget.declareGadget(gadget.state.child_gadget_url, {element: fragment,
scope: 'fg'})
.push(function (form_gadget) {
return form_gadget.render({
jio_key: gadget.state.jio_key,
doc: gadget.state.doc
});
});
});
}(document, window, rJS));
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>ERP5 Page Document</title>
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_erp5_page_bug_tracker_front.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
\ No newline at end of file
/*global window, rJS */
/*jslint nomen: true, indent: 2, maxerr: 3 */
(function (window, rJS) {
"use strict";
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("redirect", "redirect")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.declareMethod("render", function (options) {
return this.redirect({
command: 'display_stored_state',
options: {
jio_key: 'bug_module'
}
});
});
}(window, rJS, URI));
\ No newline at end of file
/*jslint indent: 2*/
/*global self, caches, fetch*/
(function (self, caches, fetch) {
"use strict";
var CACHE_NAME = 'Thu, 13 Apr 2017 12:00:04 GMT',
// Files required to make this app work offline
REQUIRED_FILES = [
// ERP5 files
'./',
'font-awesome/font-awesome-webfont.eot?v=4.6.3',
'font-awesome/font-awesome-webfont.eot?#iefix&v=4.6.3',
'font-awesome/font-awesome-webfont.woff?v=4.6.3',
'font-awesome/font-awesome-webfont.woff2?v=4.6.3',
'font-awesome/font-awesome-webfont.ttf?v=4.6.3',
'font-awesome/font-awesome-webfont.svg?v=4.6.3#fontawesomeregular',
'erp5_launcher_nojqm.js',
'gadget_erp5_nojqm.css',
'gadget_erp5_editor_panel.html',
'gadget_erp5_editor_panel.js',
'gadget_erp5_field_checkbox.html',
'gadget_erp5_field_checkbox.js',
'gadget_erp5_field_datetime.html',
'gadget_erp5_field_datetime.js',
'gadget_erp5_field_editor.html',
'gadget_erp5_field_editor.js',
'gadget_erp5_field_email.html',
'gadget_erp5_field_email.js',
'gadget_erp5_field_file.html',
'gadget_erp5_field_file.js',
'gadget_erp5_field_float.html',
'gadget_erp5_field_float.js',
'gadget_erp5_field_gadget.html',
'gadget_erp5_field_gadget.js',
'gadget_erp5_field_image.html',
'gadget_erp5_field_image.js',
'gadget_erp5_field_integer.html',
'gadget_erp5_field_integer.js',
'gadget_erp5_field_list.html',
'gadget_erp5_field_list.js',
'gadget_erp5_field_listbox.html',
'gadget_erp5_field_listbox.js',
'gadget_erp5_field_multicheckbox.html',
'gadget_erp5_field_multicheckbox.js',
'gadget_erp5_field_multilist.html',
'gadget_erp5_field_multilist.js',
'gadget_erp5_field_multirelationstring.html',
'gadget_erp5_field_multirelationstring.js',
'gadget_erp5_field_radio.html',
'gadget_erp5_field_radio.js',
'gadget_erp5_field_readonly.html',
'gadget_erp5_field_readonly.js',
'gadget_erp5_field_relationstring.html',
'gadget_erp5_field_relationstring.js',
'gadget_erp5_field_string.html',
'gadget_erp5_field_string.js',
'gadget_erp5_field_password.html',
'gadget_erp5_field_password.js',
'gadget_erp5_field_textarea.html',
'gadget_erp5_field_textarea.js',
'gadget_erp5_form.html',
'gadget_erp5_form.js',
'gadget_erp5_header.html',
'gadget_erp5_header.js',
'gadget_erp5_jio.html',
'gadget_erp5_jio.js',
'gadget_erp5_label_field.html',
'gadget_erp5_label_field.js',
'gadget_erp5_notification.html',
'gadget_erp5_notification.js',
'gadget_erp5_page_action.html',
'gadget_erp5_page_action.js',
'gadget_erp5_page_form.html',
'gadget_erp5_page_form.js',
'gadget_erp5_page_front.html',
'gadget_erp5_page_front.js',
'gadget_erp5_page_history.html',
'gadget_erp5_page_history.js',
'gadget_erp5_page_jump.html',
'gadget_erp5_page_jump.js',
'gadget_erp5_page_logout.html',
'gadget_erp5_page_logout.js',
'gadget_erp5_page_preference.html',
'gadget_erp5_page_preference.js',
'gadget_erp5_page_relation_search.html',
'gadget_erp5_page_relation_search.js',
'gadget_erp5_page_search.html',
'gadget_erp5_page_search.js',
'gadget_erp5_page_tab.html',
'gadget_erp5_page_tab.js',
'gadget_erp5_page_worklist.html',
'gadget_erp5_page_worklist.js',
'gadget_erp5_panel.html',
'gadget_erp5_panel.js',
'gadget_erp5_panel.png?format=png',
'gadget_erp5_pt_form_dialog.html',
'gadget_erp5_pt_form_dialog.js',
'gadget_erp5_pt_form_list.html',
'gadget_erp5_pt_form_list.js',
'gadget_erp5_pt_form_view.html',
'gadget_erp5_pt_form_view.js',
'gadget_erp5_pt_form_view_editable.html',
'gadget_erp5_pt_form_view_editable.js',
'gadget_erp5_pt_report_view.html',
'gadget_erp5_pt_report_view.js',
'gadget_erp5_router.html',
'gadget_erp5_router.js',
'gadget_erp5_relation_input.html',
'gadget_erp5_relation_input.js',
'gadget_erp5_search_editor.html',
'gadget_erp5_search_editor.js',
'gadget_erp5_searchfield.html',
'gadget_erp5_searchfield.js',
'gadget_erp5_sort_editor.html',
'gadget_erp5_sort_editor.js',
'gadget_global.js',
'gadget_html5_element.html',
'gadget_html5_element.js',
'gadget_html5_input.html',
'gadget_html5_input.js',
'gadget_html5_textarea.html',
'gadget_html5_textarea.js',
'gadget_html5_select.html',
'gadget_html5_select.js',
'gadget_erp5_global.js',
'gadget_jio.html',
'gadget_jio.js',
'gadget_translation.html',
'gadget_translation.js',
'gadget_translation_data.js',
'gadget_editor.html',
'gadget_editor.js',
'handlebars.js',
'jiodev.js',
'renderjs.js',
'rsvp.js',
// Bug tracker files
'gadget_erp5_bug_tracker_jio.html',
'gadget_erp5_bug_tracker_jio.js',
'gadget_erp5_page_bug_tracker_form.html',
'gadget_erp5_page_bug_tracker_form.js',
'gadget_erp5_bug_tracker_view_bug_module.html',
'gadget_erp5_bug_tracker_view_bug_module.js',
'gadget_erp5_bug_tracker_view_bug.html',
'gadget_erp5_bug_tracker_view_bug.js'
];
self.addEventListener('install', function (event) {
// Perform install step: loading each required file into cache
event.waitUntil(
caches.open(CACHE_NAME)
.then(function (cache) {
// Add all offline dependencies to the cache
return cache.addAll(REQUIRED_FILES);
})
.then(function () {
// At this point everything has been cached
return self.skipWaiting();
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
// Cache hit - return the response from the cached version
if (response) {
return response;
}
// Not in cache - return the result from the live server
// `fetch` is essentially a "fallback"
return fetch(event.request);
})
);
});
self.addEventListener("activate", function (event) {
/* Just like with the install event, event.waitUntil blocks activate on a promise.
Activation will fail unless the promise is fulfilled.
*/
event.waitUntil(
caches
/* This method returns a promise which will resolve to an array of available
cache keys.
*/
.keys()
.then(function (keys) {
// We return a promise that settles when all outdated caches are deleted.
return Promise.all(
keys
.filter(function (key) {
// Filter by keys that don't start with the latest version prefix.
// return !key.startsWith(version);
return key !== CACHE_NAME;
})
.map(function (key) {
/* Return a promise that's fulfilled
when each outdated cache is deleted.
*/
return caches.delete(key);
})
);
})
.then(function () {
self.clients.claim();
})
);
});
}(self, caches, fetch));
<!DOCTYPE html>
<html>
<!--
data-i18n=Title
-->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>ERP5 PT Frontpage</title>
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_global.js" type="text/javascript"></script>
<script src="gadget_erp5_bug_tracker_view_bug.js" type="text/javascript"></script>
</head>
<body>
<div data-gadget-url="gadget_erp5_pt_form_view.html"
data-gadget-scope="form_view"
data-gadget-sandbox="public">
</div>
</body>
</html>
\ No newline at end of file
/*global window, rJS */
/*jslint nomen: true, indent: 2, maxerr: 3 */
(function (window, rJS) {
"use strict";
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("getUrlParameter", "getUrlParameter")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.allowPublicAcquisition('updateHeader', function (argument_list) {
return this.updateHeader({
next_url: argument_list[0].next_url,
previous_url: argument_list[0].previous_url,
selection_url: argument_list[0].selection_url,
page_title: this.state.doc.portal_type + ': ' + this.state.doc.title
});
})
.declareMethod("render", function (options) {
return this.changeState({
doc: options.doc
});
})
.onStateChange(function () {
var gadget = this;
return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) {
return form_gadget.render({
erp5_document: {"_embedded": {"_view": {
"my_title": {
"description": "The name of a document in ERP5",
"title": "Title",
"default": gadget.state.doc.title,
"css_class": "",
"required": 1,
"editable": 0,
"key": "field_my_title",
"hidden": 0,
"type": "StringField"
},
"my_reference": {
"description": "The name of a document in ERP5",
"title": "Reference",
"default": gadget.state.doc.reference,
"css_class": "",
"required": 0,
"editable": 0,
"key": "field_my_reference",
"hidden": 0,
"type": "StringField"
}
}},
"_links": {
"type": {
// form_list display portal_type in header
name: ""
}
}},
form_definition: {
group_list: [[
"left",
[["my_title"], ["my_reference"]]
]]
}
});
});
});
}(window, rJS));
\ No newline at end of file
<!DOCTYPE html>
<html>
<!--
data-i18n=Title
-->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>ERP5 PT Frontpage</title>
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_global.js" type="text/javascript"></script>
<script src="gadget_erp5_bug_tracker_view_bug_module.js" type="text/javascript"></script>
</head>
<body>
<div data-gadget-url="gadget_erp5_pt_form_list.html"
data-gadget-scope="form_list"
data-gadget-sandbox="public">
</div>
</body>
</html>
\ No newline at end of file
/*global window, rJS */
/*jslint nomen: true, indent: 2, maxerr: 3 */
(function (window, rJS) {
"use strict";
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("getUrlParameter", "getUrlParameter")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.allowPublicAcquisition('updateHeader', function () {
return;
})
.declareMethod("triggerSubmit", function () {
var argument_list = arguments;
return this.getDeclaredGadget('form_list')
.push(function (gadget) {
return gadget.triggerSubmit.apply(gadget, argument_list);
});
})
.declareMethod("render", function () {
var gadget = this,
header_dict = {
page_title: 'Bugs',
filter_action: true
};
return gadget.updateHeader(header_dict)
.push(function () {
return gadget.getDeclaredGadget('form_list');
})
.push(function (form_gadget) {
var column_list = [
['title', 'Title'],
['reference', 'Reference']
];
return form_gadget.render({
erp5_document: {"_embedded": {"_view": {
"listbox": {
"column_list": column_list,
"show_anchor": 0,
"default_params": {},
"editable": 1,
"editable_column_list": [],
"key": "field_listbox",
"lines": 30,
"list_method": "portal_catalog",
"query": "urn:jio:allDocs?query=portal_type%3A%22Bug%22",
"portal_type": [],
"search_column_list": column_list,
"sort_column_list": column_list,
"title": "Bugs",
"type": "ListBox"
}
}},
"_links": {
"type": {
// form_list display portal_type in header
name: ""
}
}},
form_definition: {
group_list: [[
"bottom",
[["listbox"]]
]]
}
});
});
});
}(window, rJS));
\ No newline at end of file
erp5_web_renderjs_ui
\ No newline at end of file
GPL
\ No newline at end of file
web_site_module/bug_tracker_app
web_page_module/bug_tracker_gadget_**
\ No newline at end of file
web_site_module/bug_tracker_app
web_page_module/bug_tracker_gadget_**
\ No newline at end of file
web_page_module/bug_tracker_gadget_*
web_site_module/bug_tracker_app
web_site_module/bug_tracker_app/**
\ No newline at end of file
erp5_web_bug_tracker
\ No newline at end of file
0.1
\ No newline at end of file
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