20101001 Notizen einfügen ========================= **(3.17 Uhr)** :func:`lino.utils.jsgen.py2js` hatte einen Bug: Datumswerte wurden um einen Monat verschoben. (Denn ich hatte noch nicht mitbekommen, dass der Parameter `month` bei 0 anfängt, wenn man in Javascript ein Datum mit ``new Date(year, month, day)`` instanziert.) **(4.38 Uhr)** Tilt! Ich hab endlich verstanden, weshalb die Standardwerte im Insert-Fenster fehlten: Die kann ich natürlich nicht schon beim Generieren der :xfile:`site.js` kennen, also müssen sie dynamisch bei jedem Insert-Request ermittelt werden. Konkret: :class:`lino.ui.extjs.ext_windows.InsertWrapper` macht jetzt `record_id=-99999`, und :meth:`lino.ui.extjs.ext_ui.ExtUI.api_element_view` fängt diesen Fall ab und macht dann ReportRequest.create_instance. Jetzt fehlt noch das Datum, das ja standardmäßig ja auf heute stehen sollte. Das ist im Model, in der Felddefinition von :attr:`Note.date`. Ein `auto_now_add=True` ist hier nicht das Richtige, weil das erst in Aktion tritt, wenn das Object gespeichert wird. Aber `default=datetime.date.today` ist unser Kandidat. Schön. Jetzt sind alle Standardwerte vorbelegt im Insert-Fenster (Ausnahme: der Master bei Insert in einem Slave-Fenster. Siehe später.) Aber vorher haben wir noch ein neues Problem, wenn ich eine neu erstellte notes.Note speichern will:: ValueError: invalid literal for int() with base 10: 'root' Das liegt wahrscheinlich daran, dass username zwar unique ist, aber nicht der primary key ist. Das hieße, dass man allgemein einen ForeignKey nach :class:`users.User` nicht speichern kann. Aber `dsbe.Person.user` kann man bearbeiten und speichern. Da funktioniert es. (Upps: in `Lino.submit_detail` war noch ein kleiner Bug.) Der Unterschied ist: das PUT beim Speichern einer dsbe.Person sendet korrekterweise: user=staff,userHidden=2 Aber das POST des submit_insert einer notes.Note sendet: user=staff,userHidden=root Wie kommt er darauf, userHidden auf root zu setzen? `GET /choices/contacts/Persons/user` antwortet korrekt: { count: 3, rows: [ { text: "user", value: 1 }, { text: "staff", value: 2 }, { text: "root", value: 3 } ], title: "Choices for user" } Und auch `GET /api/notes/NotesByPerson/-99999` oder `GET /api/notes/MyNotes/-99999` antworten korrekt: { navinfo: { msg: "Row 0 of 2", next: null, prev: null, last: 10, first: 1 }, data: { body: "", language: "Deutsch", languageHidden: "de", company: null, typeHidden: null, personHidden: null, companyHidden: null, person: null, url: null, **userHidden: 3, user: "root",** date: new Date(2010,9,1), type: null, id: null, subject: null }, id: null, title: "(root 2010-10-01)" } Aber jetzt ist der Fehler von alleine verschwunden oder zumindest nicht mehr reproduzierbar. Also lassen wir das. Jetzt fehlt vor allem noch der Master bei Insert in einem Slave-Fenster. Also ich geh z.B. nach http://127.0.0.1:8000/api/contacts/Persons/79?fmt=detail&tab=4 und klicke aufs Insert der NotesByPerson. Und das Feld Person ist dann nicht ausgefüllt. Und das ist logisch, weil der InsertWrapper scheinbar keine base_params hat, denn er schickt ein `GET api/notes/NotesByPerson/-99999` (es fehlt der Master, `mk=79`). Genau. Deshalb brauchen wir die neue :js:func:`Lino.show_insert_handler`. Fertig! Also die schlimmsten Bugs beim Einfügen sind behoben: - Insert in notes.Note : Datum sollte par défaut auf heute stehen, Sprache auf Deutsch. - Beim Einfügen in einem Slave wird der Master nicht gesetzt. Jetzt zuerst ein `Check-In `__ und eine Pause. **(15.30 Uhr)** Jetzt nehme ich das Problem :srcref:`docs/tickets/5` noch mal in die Mangel (SlaveGrid-Elemente zeigen beim ersten Aufruf "Nix gefunden"). Es kommt z.B. wenn ich folgende URL aufrufe: http://127.0.0.1:8000/api/contacts/Persons/16?fmt=detail&tab=0 Das Bild wird dann nicht angezeigt, und in der Console steht **cmp is rendered but not visible: and now?**. Wie kann ein :extjs:`Ext.Component` einerseits `rendered` sein und andererseits nicht `visible`? Okay, wenn er z.B. in einem Tab ist, das momentan versteckt ist. Ist hier aber nicht der Fall, und außerdem würde der Component dann aufs show-Event reagieren. Er reagiert auf überhaupt keines der dokumentierten Events. `Ext.Component.isVisible()` ist einfach:: isVisible : function(){ return this.rendered && this.getVisibilityEl().isVisible(); }, `getVisibilityEl()` ist eine private Funktion:: getVisibilityEl : function(){ return this.hideParent ? this.container : this.getActionEl(); }, getActionEl : function(){ return this[this.actionMode]; }, Nee, das bringt alles keine Lösung. Ja, das visibilityEl is offensichtlich noch nicht visible. Aber das ist kein Component mehr und hat also kein render-Event, an das ich mich ran hängen könnte. Tilt! Idee: ich probiers einfach eine Zehntelsekunde später nochmal:: Lino.do_when_visible = function(cmp,todo) { if (cmp.isVisible()) { todo(); } else { if (cmp.rendered) { Lino.do_when_visible.defer(100,this,[cmp,todo]); } else { cmp.on('afterrender',todo,cmp,{single:true}); } } }; Das ist zwar eine Frickelslösung, aber es funktioniert! Hurra! N.B. Anfangs funktionierte es nur fürs Bild, weil für die Slave Grids noch ein anderes Problem war. Preisfrage: Wo ist der Bug in folgendem Code? :: on_master_changed : function() { cmp = this; var todo = function() { var p = cmp.ww.get_master_params(); for (k in p) cmp.getStore().setBaseParam(k,p[k]); cmp.getStore().load(); }; Lino.do_when_visible(this,todo); } Lösung: die zweite Zeile im obigen Code muss natürlich :: var cmp = this; sein. Ich alter Python-Programmierer habe eine knappe Stunde gebraucht, um das fehlende ``var`` zu finden. Ohne das ``var`` ist ``cmp`` eine globale Variable, und dann ruft er `Lino.do_when_visible` zwar brav auf jeder Grid, aber wenn die sichtbar wird, wird die ``todo`` immer nur auf der letzten Grid (NotesByPerson) aufgerufen. Ich selber habs jetzt übrigens mit `createDelegate` statt einem `this`-Ersatz gemacht, weil ich das eleganter finde:: on_master_changed : function() { var todo = function() { var p = this.ww.get_master_params(); for (k in p) this.getStore().setBaseParam(k,p[k]); this.getStore().load(); }; Lino.do_when_visible(this,todo.createDelegate(this)); } Fazit: Ich verstehe weiterhin nicht, wie ein Component im beschriebenen Fall rendered und trotzdem nicht visible sein kann, ich kriegs auch nicht reproduziert in einem einfachen showcase, aber jetzt habe ich immerhin eine funktionierende Lösung, die bis auf weiteres vollkommen reicht. Also Problem :srcref:`docs/tickets/5` ist für mich abgeschlossen. `Check-In `__ und Wochenende. **(22 Uhr)** Vor dem Schlafengehen noch schnell einen Punkt aus der :lino:`/todo` abgearbeitet: - Neue Tabelle "Ansprechpartner pro Person" mit einem Feld "Rolle" oder "Eigenschaft", dessen Auswahlliste konfigurierbar ist ('Hauptkontakt', 'DSBE', 'allgemeiner Sozialdienst', 'Schulderberatung', 'Energieberatung'). Das Feld `Person.user` kann dann raus, und `PAR->IdUsr` muss in diese Tabelle importiert werden. Im Layout2 ("Person") muss dann ``user`` ersetzt werden durch eine Tabelle von Ansprechpartnern. Konkret also vor allem 2 neue Tabellen: - CoachType : (id,name) - Coach : (user,type,person,company) Eine Vereinfachung: das Feld `Person.user` (Hauptansprechpartner) bleibt dennoch drin. Vor allem weil es sonst kompliziert und untransparent wäre, diese eine Zeile bei importierten Personen schreibgeschützt zu machen. Interessant ist zu bemerken, dass die ganze Aktion nur 45 Minuten gedauert hat, inklusive fixtures und Reorganisierung der Eingabebildschirme (aber ohne Blogschreiben). Wobei die letzten 15 Minuten eigentlich nicht zählen, denn die habe ich gebraucht um rauszufinden, dass einige Layout-Bugs doch noch dringend behoben werden sollten. Im Moment sind die meisten Bugs sichtbar im Detail von dsbe.Persons. Da kriege ich Montag noch was zu tun: - Im Tab "Kontakt" fehlen die flags, die ich noch zwischen remarks und coaching knallen will. Zumindest will ich mal sehen, wie sich das macht. Aber wenn ich das tue, ist die ganze untere hbox nicht mehr da. - Im Tab "Kontakt", box "coaching" nimmt die Grid zu viel Platz ein. Da hat Lino unnötigerweise einen VBorderPanel benutzt. Das ist nicht nötig, wenn nur ein Element vflex ist. - Im Tab "Person" nimmt die Grid zu viel Höhe. - Im Detail-Tab "Profil 1" nimmt das GridElement anfangs den ganzen Raum ein, die Felder im oberen Teil werden erst nach einem resize sichtbar. - Wieso lässt "Studien & Erfahrungen" im Tab "Person" sich höhenverstellen, aber "AG-Sperren" in "Profil 1" nicht?