feat(office): users admin UI, table rendering, and user save fixes

Add Users list/detail with ACL toggles and library people update/status APIs.
Fix project table layout and ANSI-safe cell rendering, and decode array
responses from people/status so saves no longer fail on JSON unmarshal.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-25 11:07:22 +01:00
co-authored by Cursor
parent 72844dfe24
commit 40b74eb8ab
45 changed files with 3012 additions and 438 deletions
+32 -15
View File
@@ -9,8 +9,18 @@ import (
"github.com/eslider/go-onlyoffice/cmd/office/model"
)
// UpdateTask saves title and description for a project task.
func (l *Loader) UpdateTask(ctx context.Context, taskID, title, description string) error {
// UpdateTask saves editable task fields via the typed JSON API.
func (l *Loader) UpdateTask(ctx context.Context, taskID string, fields model.FormFields) error {
return l.updateTask(ctx, taskID, fields, false)
}
// CloseTask saves fields and sets status to closed.
func (l *Loader) CloseTask(ctx context.Context, taskID string, fields model.FormFields) error {
fields.TaskStatus = model.TaskLifecycleClosed
return l.updateTask(ctx, taskID, fields, true)
}
func (l *Loader) updateTask(ctx context.Context, taskID string, fields model.FormFields, closing bool) error {
if l == nil || l.Client == nil {
return fmt.Errorf("fetch: client is nil")
}
@@ -18,19 +28,26 @@ func (l *Loader) UpdateTask(ctx context.Context, taskID, title, description stri
if err != nil {
return fmt.Errorf("task id %q: %w", taskID, err)
}
_, err = l.Client.UpdateProjectTask(onlyoffice.ProjectTaskUpdateRequest{
status := onlyoffice.ProjectTaskStatus(fields.TaskStatus)
if closing {
status = onlyoffice.ProjectTaskStatusClosed
}
req := onlyoffice.ProjectTaskUpdateRequest{
ID: id,
Title: title,
Description: description,
})
Title: fields.Primary,
Description: fields.Secondary,
Status: status,
}
if fields.ResponsibleID != "" {
req.Responsible = []string{fields.ResponsibleID}
} else if !closing {
raw, derr := l.Detail(ctx, model.Item{ID: taskID, Kind: model.KindTask})
if derr == nil {
if rid := model.TaskResponsibleIDFromRaw(raw); rid != "" {
req.Responsible = []string{rid}
}
}
}
_, err = l.Client.UpdateProjectTask(req)
return err
}
// TaskFields loads title and description for a project task item.
func (l *Loader) TaskFields(ctx context.Context, item model.Item) (title, description string, err error) {
fields, err := l.DetailForm(ctx, item)
if err != nil {
return "", "", err
}
return fields.Primary, fields.Secondary, nil
}