Commit c4acca90 authored by Romain Courteaud's avatar Romain Courteaud

[erp5_web_renderjs_ui] Render the list of modules as a grid

Use a grid of module's group to simplify navigation.
parent 5f27addc
......@@ -1731,6 +1731,44 @@ div[data-gadget-scope='maximize'] button:active {
height: 100%;
}
/**********************************************
* Front page
**********************************************/
div[data-gadget-url$="gadget_erp5_page_front.html"] > ul {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
}
div[data-gadget-url$="gadget_erp5_page_front.html"] > ul > li {
flex-shrink: 1;
vertical-align: top;
padding: 3pt;
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 0.325em;
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
}
@media not screen and (min-width: 45em) {
div[data-gadget-url$="gadget_erp5_page_front.html"] > ul > li {
flex-basis: 100%;
margin-bottom: 6pt;
}
}
@media only screen and (min-width: 45em) and (max-width: 85em), not screen and (max-width: 85em) {
div[data-gadget-url$="gadget_erp5_page_front.html"] > ul > li {
margin-right: 24pt;
margin-bottom: 24pt;
flex-basis: 20em;
}
}
div[data-gadget-url$="gadget_erp5_page_front.html"] > ul > li h2 {
font-weight: 700;
background: #085078;
color: #FFFFFF;
padding: 6pt;
}
div[data-gadget-url$="gadget_erp5_page_front.html"] > ul > li li {
padding: 3pt 6pt;
}
/**********************************************
* Icons
**********************************************/
.ui-btn-icon-top::before,
......
......@@ -16,7 +16,6 @@
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
......@@ -59,7 +58,6 @@
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
......@@ -197,7 +195,7 @@
</tuple>
<state>
<tuple>
<float>1469697744.71</float>
<float>1527842617.91</float>
<string>UTC</string>
</tuple>
</state>
......@@ -242,7 +240,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>966.58726.49878.9454</string> </value>
<value> <string>968.4008.27622.9574</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -260,7 +258,7 @@
</tuple>
<state>
<tuple>
<float>1523881593.56</float>
<float>1528376917.25</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -158,7 +158,7 @@
// Update the global links
.push(function () {
return RSVP.all([
context.getUrlFor({command: 'display_stored_state', options: {page: "front"}}),
context.getUrlFor({command: 'display', options: {page: "front"}}),
context.getUrlFor({command: 'display', options: {page: "history"}}),
context.getUrlFor({command: 'display', options: {page: "preference"}}),
context.getUrlFor({command: 'display', options: {page: "logout"}}),
......
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>967.24634.17714.15001</string> </value>
<value> <string>967.44748.35225.6109</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1526656725.01</float>
<float>1528370824.8</float>
<string>UTC</string>
</tuple>
</state>
......
<!DOCTYPE html>
<html>
<!--
data-i18n=Title
data-i18n=Domain
data-i18n=Others
-->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
......@@ -16,13 +15,24 @@
<!-- custom script -->
<script src="jiodev.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<script src="handlebars.js" type="text/javascript"></script>
<script id="card-list-template" type="text/x-handlebars-template">
{{#each card_list}}<li>
<h2>{{business_application_translated_title}}</h2>
<ul>
{{#each module_list}}
<li><a href="{{link}}">{{translated_title}}</a></li>
{{/each}}
</ul>
</li>{{/each}}
</script>
<script src="gadget_erp5_page_front.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>
<ul>
</ul>
</body>
</html>
\ No newline at end of file
......@@ -234,7 +234,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>965.28992.43927.42052</string> </value>
<value> <string>968.3747.18403.17851</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -252,7 +252,7 @@
</tuple>
<state>
<tuple>
<float>1518424688.54</float>
<float>1528376200.09</float>
<string>UTC</string>
</tuple>
</state>
......
/*global window, rJS, jIO, RSVP */
/*global window, rJS, jIO, RSVP, Handlebars */
/*jslint nomen: true, indent: 2, maxerr: 3, maxlen: 80 */
(function (window, rJS, jIO, RSVP) {
(function (window, rJS, jIO, RSVP, Handlebars) {
"use strict";
rJS(window)
var gadget_klass = rJS(window),
card_list_template_source = gadget_klass.__template_element
.getElementById("card-list-template")
.innerHTML,
card_list_template = Handlebars.compile(card_list_template_source);
gadget_klass
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("getUrlParameter", "getUrlParameter")
.declareAcquiredMethod("translate", "translate")
.declareAcquiredMethod("getUrlForList", "getUrlForList")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod("jio_allDocs", "jio_allDocs")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.allowPublicAcquisition('updateHeader', function () {
return;
})
.allowPublicAcquisition('getUrlForList', function (argument_list) {
var i,
options_list = argument_list[0],
result_list = [];
for (i = 0; i < options_list.length; i += 1) {
if (options_list[i].command === 'index') {
result_list.push({
command: 'display_stored_state',
options: {jio_key: options_list[i].options.jio_key}
});
} else {
result_list.push(options_list[i]);
}
}
return this.getUrlForList.apply(this, [result_list]);
})
.allowPublicAcquisition('jio_allDocs', function (argument_list) {
// ERP5 does not support filtering/sorting on translated properties
// Fetch the list of all modules from ERP5
// and filter/sort it manually after
var allDocs_options = argument_list[0],
.declareMethod('render', function renderHeader() {
var gadget = this,
select_list = ['translated_title',
'business_application_translated_title', 'uid', 'id',
'title', '__id'],
new_allDocs_options = {
limit: allDocs_options.limit,
query:
'(parent_uid:"0" AND meta_type:"ERP5 Folder" AND id:"%_module")',
select_list: select_list,
sort_on: []
},
context = this;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
context.jio_allDocs(new_allDocs_options),
context.getUrlParameter('extended_search')
]);
})
'business_application_translated_title', 'id'];
// First, get the list of modules
return gadget.jio_allDocs({
select_list: select_list,
query: '(parent_uid:"0" AND meta_type:"ERP5 Folder" AND id:"%_module")',
limit: 1000
})
.push(function (result_list) {
// ERP5 catalog can't sort by translated property
// Sort manually with jIO
var data_rows = [],
i,
len = result_list[0].data.total_rows,
query = result_list[1] || "";
len = result_list.data.total_rows;
for (i = 0; i < len; i += 1) {
// queries do not accept null value
result_list[0].data.rows[i].value
result_list.data.rows[i].value
.business_application_translated_title =
result_list[0].data.rows[i].value
result_list.data.rows[i].value
.business_application_translated_title || '';
result_list[0].data.rows[i].value.id =
result_list[0].data.rows[i].id;
data_rows.push(result_list[0].data.rows[i].value);
result_list.data.rows[i].value.id =
result_list.data.rows[i].id;
data_rows.push(result_list.data.rows[i].value);
}
return jIO.QueryFactory.create(query)
.exec(data_rows, {query: query, select_list: select_list,
sort_on: allDocs_options.sort_on});
return jIO.QueryFactory.create('')
.exec(data_rows,
{query: '', select_list: select_list,
sort_on: [['business_application_translated_title',
'ascending'],
['translated_title', 'ascending']]});
})
.push(function (document_list) {
var len = document_list.length,
var url_dict_list = [],
i,
result = [];
len = document_list.length;
// Calculate all module's urls
for (i = 0; i < len; i += 1) {
result.push({id: document_list[i].id, value: document_list[i]});
url_dict_list.push({
command: 'display_stored_state',
options: {jio_key: document_list[i].id}
});
}
return {data: {rows: result, total_rows: len}};
});
})
.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: 'Modules',
page_icon: 'puzzle-piece',
filter_action: true
};
return gadget.getUrlFor({command: 'display'})
.push(function (front_url) {
header_dict.front_url = front_url;
return gadget.updateHeader(header_dict);
})
.push(function () {
return gadget.getDeclaredGadget('form_list');
// Add global url calculation
url_dict_list.push({command: 'display'});
return RSVP.all([
document_list,
gadget.translate('Others'),
gadget.getUrlForList(url_dict_list)
]);
})
.push(function (form_gadget) {
var column_list = [
['translated_title', 'Title'],
['business_application_translated_title', 'Domain']
];
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": 1000,
"list_method": "portal_catalog",
"query": "urn:jio:allDocs?query=parent_uid%3A%220%22%20AND" +
"%20meta_type%3A%22ERP5%20Folder%22%20AND" +
"%20id%3A%22%25_module%22",
"portal_type": [],
"search_column_list": column_list,
"sort_column_list": column_list,
"sort": [["translated_title", "ASC"]],
"title": "Modules",
"type": "ListBox"
.push(function (result_list) {
var document_list = result_list[0],
translated_other_title = result_list[1],
url_list = result_list[2],
len = document_list.length,
i,
card_list = [],
module_list = [],
other_module_list = [],
current_business_application_title = '';
function pushNewCard() {
if (module_list) {
if (current_business_application_title === '') {
other_module_list = module_list;
} else {
card_list.push({
business_application_translated_title:
current_business_application_title,
module_list: module_list
});
}
}},
"_links": {
"type": {
// form_list display portal_type in header
name: ""
}
}},
form_definition: {
group_list: [[
"bottom",
[["listbox"]]
]]
}
}
for (i = 0; i < len; i += 1) {
// Inject the module url into the document
document_list[i].link = url_list[i];
// Create card if needed
if (document_list[i].business_application_translated_title !==
current_business_application_title) {
pushNewCard();
module_list = [];
current_business_application_title =
document_list[i].business_application_translated_title;
}
module_list.push(document_list[i]);
}
pushNewCard();
if (other_module_list) {
card_list.push({
business_application_translated_title: translated_other_title,
module_list: other_module_list
});
}
gadget.element.querySelector('ul').innerHTML = card_list_template({
card_list: card_list
});
return gadget.updateHeader({
page_title: 'Modules',
page_icon: 'puzzle-piece',
front_url: url_list[i]
});
});
});
}(window, rJS, jIO, RSVP));
\ No newline at end of file
}(window, rJS, jIO, RSVP, Handlebars));
\ No newline at end of file
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>967.35005.6239.57258</string> </value>
<value> <string>968.3771.7664.16349</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1526303943.53</float>
<float>1528362121.19</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -1956,6 +1956,45 @@ div[data-gadget-scope='maximize'] button {
}
}
/**********************************************
* Front page
**********************************************/
div[data-gadget-url$="gadget_erp5_page_front.html"] {
> ul {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
> li {
flex-shrink: 1;
@media @smartphone {
flex-basis: 100%;
margin-bottom: @margin-size;
}
@media @tablet, @desktop {
margin-right: @quadruple-margin-size;
margin-bottom: @quadruple-margin-size;
flex-basis: 20em;
}
vertical-align: top;
padding: @half-margin-size;
border: @border;
border-radius: @border-radius;
box-shadow: 2px 2px 2px rgba(0,0,0,.15);
h2 {
font-weight: @header-font-weight;
background: @colorheaderbackground;
color: @white;
padding: @margin-size;
}
li {
padding: @half-margin-size @margin-size;
}
}
}
}
/**********************************************
* Icons
**********************************************/
......
......@@ -24,6 +24,13 @@
<td></td>
</tr>
<!-- Check that there is a card -->
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-url='${base_url}/web_site_module/renderjs_runner/gadget_erp5_page_front.html']//ul/li/h2[text()='Others']</td>
<td></td>
</tr>
<!-- Generate links to module -->
<tr>
<td>waitForElementPresent</td>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testPageFrontSearchModuleList</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Page Front</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Page Front</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Go to the list of modules and check that it is possible to search -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/?page=front</td>
<td></td>
</tr>
<!-- Wait for gadget to be loaded -->
<tr>
<td>waitForElementPresent</td>
<td>//div[@data-gadget-url='${base_url}/web_site_module/renderjs_runner/gadget_erp5_page_front.html']</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_listbox_loaded" />
<!-- All entries to module -->
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='m']//a[text()='Bars' and contains(@href, '#!display_stored_state') and contains(@href, 'n.jio_key=bar_module')]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='m']//a[text()='Foos' and contains(@href, '#!display_stored_state') and contains(@href, 'n.jio_key=foo_module')]</td>
<td></td>
</tr>
<tal:block tal:define="search_query python: 'Foos'">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/search_in_form_list" />
</tal:block>
<!-- Less entries to module -->
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='m']//a[text()='Bars' and contains(@href, '#!display_stored_state') and contains(@href, 'n.jio_key=bar_module')]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='m']//a[text()='Foos' and contains(@href, '#!display_stored_state') and contains(@href, 'n.jio_key=foo_module')]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -7,7 +7,7 @@
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Search on translated module page</td></tr>
<tr><td rowspan="1" colspan="3">Test translated module page</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
......@@ -48,64 +48,6 @@
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text() = "guolv"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//button[text() = "guolv"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@name='heard_about']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@class="filter_item_container"]/div[1]//select</td>
<td></td>
</tr>
<tr>
<td>select</td>
<td>//div[@class="filter_item_container"]/div[1]//select</td>
<td>index=0</td>
</tr>
<tr>
<td>type</td>
<td>//div[@class="filter_item_container"]/div[1]//input</td>
<td>foo_mokuai</td>
</tr>
<tr>
<td>click</td>
<td>//button[@class="submit responsive ui-last-child ui-btn ui-btn-icon-left ui-icon-check"]</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//a[text() = 'foo_mokuai']</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -17,58 +17,18 @@
</tr>
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/?page=front</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="search_query python: 'Foos'">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/search_in_form_list" />
</tal:block>
<!-- Check sorted by modification date -->
<tr>
<td colspan="3"><b>Check sorted by modification date</b></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_sort" />
<tr>
<td>waitForElementPresent</td>
<td>//div[@class='sort_item_container ui-controlgroup ui-corner_all']//select</td>
<td></td>
</tr>
<tr>
<td>verifyValue</td>
<td>//div[@class='sort_item_container ui-controlgroup ui-corner_all']/div[1]//select[1]</td>
<td>translated_title</td>
</tr>
<tr>
<td>verifyValue</td>
<td>//div[@class='sort_item_container ui-controlgroup ui-corner_all']/div[1]//select[2]</td>
<td>ascending</td>
</tr>
<!-- Go to another page than search -->
<tr>
<td colspan="3"><b>Go to another page than search</b></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//a[@data-i18n='Preferences']</td>
<td></td>
</tr>
<tr>
<td>waitForTextPresent</td>
<td>Language</td>
<td>${base_url}/web_site_module/renderjs_runner/#/?page=worklist</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<!-- Check the the global modules link restore the search state -->
<!-- Check the global modules link -->
<tr>
<td colspan="3"><b>Check the the global modules link restore the search state</b></td>
<td colspan="3"><b>Check the global modules link</b></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//a[@data-i18n='Modules' and contains(@href, '#!display_stored_state') and contains(@href, 'n.page=front')]</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//a[@data-i18n='Modules' and contains(@href, '#!display') and contains(@href, 'n.page=front')]</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
......@@ -80,10 +40,6 @@
<td>//div[@data-gadget-url='${base_url}/web_site_module/renderjs_runner/gadget_erp5_page_front.html']</td>
<td></td>
</tr>
<tal:block tal:define="parsed_query python: '';
search_query python: 'Foos'">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" />
</tal:block>
</tbody></table>
</body>
......
......@@ -30,7 +30,7 @@
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tr>
<td>waitForElementPresent</td>
......
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