# 20140206 (Thursday, 06 February 2014)¶

## Release for Roger¶

Yesterday evening I announced a release of Renamed “Lino Faggio” to “Lino Voga” for Roger, but I had to postpone this because there were quite a lot of last-minute surprises:

• How to use git for stepping back?
• lino_faggio.migrate wasn’t yet ready.
• Yet another thing which indicates that set_detail_tab is not good: there was a problem with the vat_id field of a company. Last week I had moved this field to Partner, during migration I noticed that this was a wrong decision, the field must remain in contacts.Company. It took me quite some time to find where this field was being added to the contacts.PartnerDetail. Now I use a sales.PartnerDetailMixin. This also solves the problem of ordering of the PartnerDetail tabs in Renamed “Lino Faggio” to “Lino Voga”: sales should come before ledger although logically (technically) it is the opposite.
• Enter, Ctrl-Enter and Ctrl-S
• ComboBox and the TAB key

## How to use git for stepping back?¶

On a production site I have a repositories directory whith 5 git clones: atelier, djangosite, north, lino and lino_faggio. I wrote a script called “pull” which does a git pull all those 5 directories. But what if I don’t like the new version and want to step back? How should I organize my upgrade so that I can step back to the revision that were master at a certain timestamp?

repositories/lino

$git log commit 3e501c9d6bd4150681abce6ad0f7f323a05113dd Author: Luc Saffre <luc.saffre@gmail.com> Date: Tue Dec 10 21:06:44 2013 +0200 http://docs.lino-framework.org/blog/2013/1210.html commit a300827274f59f5eb07964e741319889f87dd6e6 Author: Luc Saffre <luc.saffre@gmail.com> Date: Tue Dec 10 08:35:28 2013 +0200 http://docs.lino-framework.org/blog/2013/1210.html  repositories/lino-faggio commit bc0697447443c50987503c5820f82f8aca77dfae Author: Luc Saffre <luc.saffre@gmail.com> Date: Tue Dec 10 21:06:56 2013 +0200 http://docs.lino-framework.org/blog/2013/1210.html commit 823431e30e3ea477bebad473eaabdc36a23e0af0 Author: Luc Saffre <luc.saffre@gmail.com> Date: Tue Dec 10 14:41:20 2013 +0200 http://docs.lino-framework.org/blog/2013/1210.html  repositories/north: commit 3767b78ca3edc94ef7b1572c17dc44fffb316cfa Author: Luc Saffre <luc.saffre@gmail.com> Date: Thu Dec 5 19:09:25 2013 +0200 http://docs.lino-framework.org/blog/2013/1205.html  ## Enter, Ctrl-Enter and Ctrl-S¶ I start to understand more about our Ctrl-Enter/Enter problem. Having ENTER bound to save() is indeed necessary within FormPanels used for insert actions. So I decided to take Joe’s approach (instead of mine) as a quick workaround before solving the problem more deeply (I’d like to add a “Insert and add new record” button to the InsertFormPanels, and also make the set of available insert submit buttons configurable per model or actor) But with Joe’s solution I get a JavaScript error: TypeError: e.target is undefined After inspecting ext-all-debug.js I found that my version of ExtJS passes two arguments (key, event) to the handler function, so only the following variant of Joe’s solution works for me: fn: function(k, e) { if(e.target.type === 'textarea' && !e.ctrlKey) { return true; } this.on_ok(); }  I verified that both ExtJS 3.3.1, and ExtJS 3.4 officially do it like this: it will call the function with this signature (…): (String key, Ext.EventObject e) ## ComboBox and the TAB key¶ Cool! I managed to fix another old problem for keyboard users: When entering data into a FormPanel using the keyboard, then I recommend to use the TAB key for skipping to the next input field. But Lino until now had a strange behaviour: in order to select a value from a ComboBox using the keyboard you must first hit RET. Pressing TAB will restore the previous value! As if you had typed ESC! This is related to a strange piece of code in Ext.form.ComboBox.initEvents: this.keyNav = new Ext.KeyNav(this.el, { (...) "enter" : function(e){ this.onViewClick(); }, "esc" : function(e){ this.collapse(); }, "tab" : function(e){ if (this.forceSelection === true) { this.collapse(); } else { this.onViewClick(false); } return true; },  ComboBox.forceSelection is “true to restrict the selected value to one of the values in the list, false to allow the user to set arbitrary text into the field” (quote from the docs). And this is an important feature. Lino manages this option automatically: it is usually set to false, except for Learning Comboboxes. I don’t understand why the ExtJS authors decided to give to forceSelection option this surprising side-effect. But then I discovered that the test is done here for the exact true value (using the triple equal sign ===), while at the place where it really matters, they just test for the boolean equivalent: if(!rec && this.forceSelection){  I don’t know whether this was intended, but it suits me very well: I can now set forceSelection to some non-empty text and voilà: forceSelection is enabled, but :kbdTAB now selects the value before jumping to the next field. ## Miscellaneous¶ • Bei Auswahl Kursleiter steht jetzt nicht mehr die Kursleiterart in Klammern hinter dem Namen. • Kursserie einfügen: auch Felder Thema und Kursleiter • Neue Partner (Kursleiter, Schüler, Organisationen, sonstige) haben jetzt par défaut “Belgien” als Land (genauer gesagt das Land des Site-Besitzers (system.SiteConfig.site_company) ## Attestations¶ Continued on docs/tickets/93. How to issue a presence attestation (Anwesenheitsbescheinigung)? Das ist eine der heftigsten Änderungen in der Benutzerschnittstelle, die ich vorhabe. Bisher sagt man am Empfang “Bitte eine Bescheinigung (F6)” und TIM fragt darauf “Welche?”. In Lino würde ich das gerne andersrum machen: Um z.B. eine Bescheinung auszustellen, dass jemand anwesend war, gibt man zunächst die Anwesenheit ein (bzw. findet sie am Bildschirm) und klickt dort auf “Bescheinigung”. Manuelle Eingabe der Uhrzeit ist dann (im Normalfall) nicht mehr nötig, weil Lino die ja kennt. Code changes: • lino.modlib.cal now supports overriding of the cal.Guest model. • lino_welfare.modlib.cal now uses this to make Guest an Attestable. • lino.modlib.attestations.AttestationType has a new field content_type. TODO: • Continue on the issue_attestation action: how to configure or customize whether the document is to be printed directly without displaying a detail window. ## Release for Roger¶ ## Getting a pull request¶ Joe converted the ExtJS HTML generating to a system based on templates and sent a pull request. Wow! That was a great work! I have local changes because I worked today, but this time there are no conflicts. Here is my git status: # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: docs/blog/2014/0206.rst # modified: docs/warnings_html.txt # modified: lino/locale/de/LC_MESSAGES/django.mo # modified: lino/locale/de/LC_MESSAGES/django.po # modified: lino/locale/django.pot # modified: lino/locale/et/LC_MESSAGES/django.po # modified: lino/locale/fr/LC_MESSAGES/django.po # modified: lino/locale/nl/LC_MESSAGES/django.po # modified: lino/locale/pt-br/LC_MESSAGES/django.po # modified: lino/modlib/attestations/models.py # modified: lino/modlib/cal/models_guest.py # modified: lino/modlib/contacts/models.py # modified: lino/modlib/extensible/__init__.py # modified: lino/modlib/reception/models.py # modified: lino/project_info.py # modified: lino/projects/docs/settings.py # modified: lino/utils/xmlgen/sepa/validate.py # no changes added to commit (use "git add" and/or "git commit -a")  Before committing my local changes I merge the pull request using the GitHub web interface. Now I commit my local changes. Oops, this gives: $ git commit -a -m http://docs.lino-framework.org/blog/2014/0206.html
[master ac2d661] http://docs.lino-framework.org/blog/2014/0206.html
17 files changed, 1768 insertions(+), 1377 deletions(-)
$git push To git@github.com:lsaffre/lino.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'git@github.com:lsaffre/lino.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first merge the remote changes (e.g., hint: 'git pull') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.  Yes, in fact git is right. I must first pull Joe’s changes: $ git pull
remote: Counting objects: 20, done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 20 (delta 7), reused 0 (delta 0)
Unpacking objects: 100% (20/20), done.
From github.com:lsaffre/lino
ec134a1..4fc982c  master     -> origin/master
Merge made by the 'recursive' strategy.
lino/core/web.py                          |   7 ++-
lino/modlib/extjs/config/extjs/index.html | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lino/modlib/extjs/ext_renderer.py         | 327 +++++++++++++++---------------------------------------------------------------------------------
3 files changed, 301 insertions(+), 278 deletions(-)
create mode 100644 lino/modlib/extjs/config/extjs/index.html


Now I can do:

\$ git push
Counting objects: 92, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (44/44), done.
Writing objects: 100% (49/49), 42.57 KiB | 0 bytes/s, done.
Total 49 (delta 32), reused 0 (delta 0)
To git@github.com:lsaffre/lino.git


And that was it! At least the Lino test suite passes.

But when I runserver for Renamed “Lino Faggio” to “Lino Voga” and point my browser to it, then I get an UndefinedError “‘lng’ is undefined” in /lino/modlib/extensible/__init__.py in get_js_includes, line 88. It seems that this was a typo, I just needed to replace lng by languages in the new file /lino/modlib/extensible/config/extjs/index.html.

Committed this one, too. And now I continue to work for the promised release.

## Release for Roger¶

Basically the upgrade consisted of the following actions:

# cd /var/www/vhosts/eiche
# ./backup.sh
# ./pull.sh
# cd lino
# . env/bin/activate
# python manage.py run /var/backups/lino/eiche/20140206_184532/restore.py