Commit 5c4a03f6 authored by Nicolas Wavrant's avatar Nicolas Wavrant

erp5_web_renderjs_ui: datetime field formats date in the interface language

Also hide seconds as it weights down the interface, and to follow the behavior of XML style
parent 74f37187
......@@ -32,7 +32,7 @@
];
rJS(window)
.declareAcquiredMethod('getSelectedLanguage', 'getSelectedLanguage')
.declareMethod('render', function (options) {
var field_json = options.field_json || {},
state_dict = {
......@@ -228,24 +228,52 @@
} else {
queue
.push(function (gadget_list) {
var text_content = "",
return RSVP.all([
gadget.getSelectedLanguage(),
gadget_list
]);
})
.push(function (result_list) {
var language = result_list[0],
gadget_list = result_list[1],
text_content = "",
state_date,
locale_formatted_state_date,
offset_time_zone;
if (gadget.state.value) {
state_date = new Date(gadget.state.value);
/* Ideally we would like to use {timeStyle: "short"} as option
* to hide seconds. Unfortunately it doesn't work in older
* versions of firefox. Luckily, by using
* {hour: "numeric", minute: "numeric"}
* it hides seconds, and still respects the locale.
* >> date = new Date(2019, 1, 1, 1, 1)
* >> date.toLocaleTimeString(
* 'en', {hour: "numeric", minute: "numeric"}
* )
* "1:01 AM"
* >> date.toLocaleTimeString(
* 'fr', {hour: "numeric", minute: "numeric"}
* )
* "01:01"
*/
locale_formatted_state_date = state_date.toLocaleTimeString(
language,
{hour: "numeric", minute: "numeric"}
);
if (gadget.state.timezone_style) {
text_content = state_date.toLocaleDateString();
text_content = state_date.toLocaleDateString(language);
if (!gadget.state.date_only) {
text_content += " " + state_date.toLocaleTimeString();
text_content += " " + locale_formatted_state_date;
}
} else {
//get timezone difference between server and local browser
offset_time_zone = timezone + (state_date.getTimezoneOffset() / 60);
//adjust hour in order to get correct date time string
state_date.setUTCHours(state_date.getUTCHours() + offset_time_zone);
text_content = state_date.toLocaleDateString();
text_content = state_date.toLocaleDateString(language);
if (!gadget.state.date_only) {
text_content += " " + state_date.toLocaleTimeString();
text_content += " " + locale_formatted_state_date;
  • @Nicolas @xiaowu.zhang in this branch, we use locale_formatted_state_date, but state_date was modified just above ( state_date.setUTCHours(state_date.getUTCHours() + offset_time_zone); ). I think we should call toLocaleTimeString again on the modified date.

    Maybe move this

                  locale_formatted_state_date = state_date.toLocaleTimeString(
                    language,
                    {hour: "numeric", minute: "numeric"}
                  );
    

    in a function and call it in both branches of this if ?

    /cc @romain

  • also, this seems not correct:

                    state_date.setUTCHours(state_date.getUTCHours() + offset_time_zone);

    what if local timezone is before UTC and the local time should be another day ?

    what if timezone is something like +5:30 ?

    This is not something from this change, the code before looks incorrect.

    Edited by Jérome Perrin
  • @jerome , @romain

    I have a fix here : e589ded7

    Tests pass locally. Is it OK to push ?

  • great, thank you !

    We can fix the cases of timezones before UTC or where the offset is not a multiple of one hour later, that commit already fixes the regression for most of us.

    I'm wondering how we can get a test failing before the fix. Things like https://github.com/plaa/TimeShift-js seems hard to integrate reliably because it would mean that from Zelenium we have to patch Date in the gadget namespace. Maybe we could run firefox with a different timezone using an approach like 7a91ddf5 ? that would not work when running on remote selenium (like we did with saucelabs), but if this approach works, maybe we could make a test class which runs timezone functional tests in various timezones (for example: Europe/Paris, America/Sao_Paulo, Asia/Colombo)

  • that commit already fixes the regression for most of us.

    That's not exact. This commit fixes the regression. It will still be wrong in some cases, but same as before, so it's definitely an improvement and I believe we can push this commit on master.

  • What test* is supposed to fail ? erp5_web_renderjs_ui_test:testFunctionalRJSDateTimeField ?

    Edited by Jérome Perrin
  • run firefox with a different timezone using an approach like 7a91ddf5 ?

    there was a mistake in this change, I'm trying again as 74126d27

  • without adding a test, the issue will come back next time one update the field code.

    @Nicolas please add a test reproducing the expected behaviour you want to achieve.

  • The proof of concept from 74126d27 seem to work. If we run firefox with TZ=Europe/Paris, then erp5_web_renderjs_ui_test:testFunctionalRJSDateTimeField fail as expected:

    image ... image

    image

    In this test, zope runs as UTC and browser as Europe/Paris. This never failed on master because both zope and browser are on UTC.

    How do you think about this approach ? We could run this test and other tests depending on the browser timezone on multiple timezones like this ( before UTC, after UTC etc ) ?

  • Wouldn't it possible to write a test where I set a date with a timezone ?

    I tried in my instance to set this date on a document :

    Screenshot_2020-04-17_at_18.59.45

    In the new interface (without this commit), it renders as :

    Screenshot_2020-04-17_at_19.01.27

    But this seems super buggy to me, as if I hide the timezone in the field definition I get :

    Screenshot_2020-04-17_at_19.02.12

  • (So we assert on a buggy behavior of the old interface, but at least the test is easy to write)

  • Wouldn't it possible to write a test where I set a date with a timezone ?

    Isn't it another case ?

    But this seems super buggy to me, as if I hide the timezone in the field definition I get :

    Screenshot_2020-04-17_at_19.02.12

    "hide timezone" just does not show timezone, in a sense it's correct.

  • Wouldn't it possible to write a test where I set a date with a timezone ?

    Isn't it another case ?

    If the date is in a timezone different from server and from client, then I think it will be testing the behavior we want.

  • Ah yes, if we can consider that this specific problem is purely a client side bug that is independant of the server timezone, then it's probably enough to test it with a date that is different from client timezone.

    That said, now that we have timezone related code in javascript, it could be nice one day to be able to test this under different timezones, but you are right, let's first fix this bug and later we can consider improving this part of our tests.

  • @romain : my first plan to test was to create a bar and calling on it .setStartDate(some_date_in_a_timezone_different_from_server_and_client). I notice that the portal type Bar doesn't have property sheets. Is it on purpose ?

  • No idea. Try with a Foo maybe

Please register or sign in to reply
}
}
}
......
......@@ -142,114 +142,122 @@
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1514233879.31</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</tuple>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1514233879.31</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>965.12118.35525.1655</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1517930509.55</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>980.55051.50282.19404</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1577775957.85</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -153,6 +153,19 @@
<td>glob:${now}*</td>
</tr>
<!-- Seconds should also be invisible in non-editable mode,
and that output follows locale (here "en") -->
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/toggle_editable_mode" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/verify_is_non_editable_mode" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>assertText</td>
<td>//div[@data-gadget-scope='field_my_start_date']//p</td>
<td>regexp:1?\d/[123]?\d/20\d\d \d\d?:\d\d (AM|PM)</td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -82,7 +82,7 @@
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_start_date']//div[@data-gadget-scope='field']//p[contains(text(), '11:00:00')]</td>
<td>//div[@data-gadget-scope='field_my_start_date']//div[@data-gadget-scope='field']//p[contains(text(), '11:00')]</td>
<td></td>
</tr>
......
......@@ -82,7 +82,7 @@
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_start_date']//div[@data-gadget-scope='field']//p[contains(text(), '11:00:00')]</td>
<td>//div[@data-gadget-scope='field_my_start_date']//div[@data-gadget-scope='field']//p[contains(text(), '11:00')]</td>
<td></td>
</tr>
......
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