Backend improvements: views, fields_get, session, RPC stubs

- Improved auto-generated list/form/search views with priority fields,
  two-column form layout, statusbar widget, notebook for O2M fields
- Enhanced fields_get with currency_field, compute, related metadata
- Fixed session handling: handleSessionInfo/handleSessionCheck use real
  session from cookie instead of hardcoded values
- Added read_progress_bar and activity_format RPC stubs
- Improved bootstrap translations with lang_parameters
- Added "contacts" to session modules list

Server starts successfully: 14 modules, 93 models, 378 XML templates,
503 JS modules transpiled — all from local frontend/ directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc
2026-03-31 23:16:26 +02:00
parent 8741282322
commit 9c444061fd
32 changed files with 3416 additions and 148 deletions

View File

@@ -97,6 +97,16 @@ func (rs *Recordset) Create(vals Values) (*Recordset, error) {
// Phase 1: Apply defaults for missing fields
ApplyDefaults(m, vals)
// Apply dynamic defaults from model's DefaultGet hook (e.g., DB lookups)
if m.DefaultGet != nil {
dynDefaults := m.DefaultGet(rs.env, nil)
for k, v := range dynDefaults {
if _, exists := vals[k]; !exists {
vals[k] = v
}
}
}
// Add magic fields
if rs.env.uid > 0 {
vals["create_uid"] = rs.env.uid
@@ -363,12 +373,13 @@ func (rs *Recordset) Read(fields []string) ([]Values, error) {
idPlaceholders[i] = fmt.Sprintf("$%d", i+1)
}
// Fetch without ORDER BY — we'll reorder to match rs.ids below.
// This preserves the caller's intended order (e.g., from Search with a custom ORDER).
query := fmt.Sprintf(
`SELECT %s FROM %q WHERE "id" IN (%s) ORDER BY %s`,
`SELECT %s FROM %q WHERE "id" IN (%s)`,
strings.Join(columns, ", "),
m.table,
strings.Join(idPlaceholders, ", "),
m.order,
)
rows, err := rs.env.tx.Query(rs.env.ctx, query, args...)
@@ -377,7 +388,8 @@ func (rs *Recordset) Read(fields []string) ([]Values, error) {
}
defer rows.Close()
var results []Values
// Collect results keyed by ID so we can reorder them.
resultsByID := make(map[int64]Values, len(rs.ids))
for rows.Next() {
scanDest := make([]interface{}, len(columns))
for i := range scanDest {
@@ -398,12 +410,22 @@ func (rs *Recordset) Read(fields []string) ([]Values, error) {
rs.env.cache.Set(m.name, id, name, val)
}
}
results = append(results, record)
if id, ok := toRecordID(record["id"]); ok {
resultsByID[id] = record
}
}
if err := rows.Err(); err != nil {
return nil, err
}
// Reorder results to match the original rs.ids order.
results := make([]Values, 0, len(rs.ids))
for _, id := range rs.ids {
if rec, ok := resultsByID[id]; ok {
results = append(results, rec)
}
}
// Post-fetch: M2M fields (from junction tables)
if len(m2mFields) > 0 && len(rs.ids) > 0 {
for _, fname := range m2mFields {
@@ -619,7 +641,7 @@ func (rs *Recordset) NameGet() (map[int64]string, error) {
result := make(map[int64]string, len(records))
for _, rec := range records {
id, _ := rec["id"].(int64)
id, _ := toRecordID(rec["id"])
name, _ := rec[recName].(string)
result[id] = name
}