feat(office): mail preview, infinite scroll, pane resize, and scrollbars
Release Please / Release Please (push) Skipped
Tests / Test (Go 1.22) (push) Skipped
Tests / Test (Go stable) (push) Skipped
Release / GoReleaser (push) Failing after 38s

Polish the office TUI with proportional pane layout, drag resize, live
filtering, HTML mail preview, paginated mail lists, overflow scrollbars,
flattened navigation, and project save/status fixes; add UpdateProjectStatus.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-24 22:23:25 +01:00
co-authored by Cursor
parent 92285e439d
commit 72844dfe24
45 changed files with 2611 additions and 206 deletions
+33 -12
View File
@@ -10,29 +10,50 @@ import (
)
// SaveItem persists editable form fields for supported entity kinds.
func (l *Loader) SaveItem(ctx context.Context, item model.Item, title, description string) error {
func (l *Loader) SaveItem(ctx context.Context, item model.Item, fields model.FormFields) error {
if l == nil || l.Client == nil {
return fmt.Errorf("fetch: client is nil")
}
switch item.Kind {
case model.KindTask:
return l.UpdateTask(ctx, item.ID, title, description)
return l.UpdateTask(ctx, item.ID, fields.Primary, fields.Secondary)
case model.KindProject:
id, err := strconv.Atoi(item.ID)
if err != nil {
return err
}
_, err = l.Client.UpdateProject(onlyoffice.ProjectUpdateRequest{
ID: id,
Title: title,
Description: description,
})
return err
return l.saveProject(ctx, item.ID, fields)
default:
return fmt.Errorf("save not supported for %s", item.Kind)
}
}
func (l *Loader) saveProject(ctx context.Context, projectID string, fields model.FormFields) error {
id, err := strconv.Atoi(projectID)
if err != nil {
return err
}
if fields.ResponsibleID == "" {
raw, derr := l.Detail(ctx, model.Item{ID: projectID, Kind: model.KindProject})
if derr == nil {
fields.ResponsibleID = model.ResponsibleIDFromRaw(raw)
}
}
req := onlyoffice.ProjectUpdateRequest{
ID: id,
Title: fields.Primary,
Description: fields.Secondary,
}
if fields.ResponsibleID != "" {
req.ResponsibleID = fields.ResponsibleID
}
if _, err := l.Client.UpdateProject(req); err != nil {
return err
}
if fields.HasStatus {
if _, err := l.Client.UpdateProjectStatus(id, string(fields.Status)); err != nil {
return err
}
}
return nil
}
// DetailForm loads form field values for the detail pane.
func (l *Loader) DetailForm(ctx context.Context, item model.Item) (model.FormFields, error) {
raw, err := l.Detail(ctx, item)