ListWorkspaces returns every non-deleted workspace, unordered by user. This is intended for admin-panel cross-tenant views and the pre-auth/fresh-install bootstrap. End-user workspace switchers should call GetUserWorkspaces instead, which scopes to the user's memberships.
()
| 13 | // pre-auth/fresh-install bootstrap. End-user workspace switchers should |
| 14 | // call GetUserWorkspaces instead, which scopes to the user's memberships. |
| 15 | func (s *Store) ListWorkspaces() ([]models.Workspace, error) { |
| 16 | // BUG-1481: workspaces.updated_at only moves when the workspace row |
| 17 | // itself changes (rename, settings, members) — it does NOT reflect |
| 18 | // item activity inside the workspace. We surface the latter via |
| 19 | // MAX(items.updated_at) and expose the later of the two as the |
| 20 | // workspace's effective UpdatedAt, so `pad workspace list` answers |
| 21 | // "where is work happening?" rather than "when was this row last |
| 22 | // renamed?". Done in two steps (scalar subquery + Go-side max) to |
| 23 | // stay portable across SQLite (no GREATEST) and Postgres. |
| 24 | rows, err := s.db.Query(s.q(` |
| 25 | SELECT w.id, w.name, w.slug, w.owner_id, COALESCE(ou.username, ''), w.description, w.settings, w.source, w.created_at, w.updated_at, |
| 26 | (SELECT MAX(i.updated_at) FROM items i WHERE i.workspace_id = w.id AND i.deleted_at IS NULL) |
| 27 | FROM workspaces w |
| 28 | LEFT JOIN users ou ON ou.id = w.owner_id |
| 29 | WHERE w.deleted_at IS NULL |
| 30 | ORDER BY w.name ASC |
| 31 | `)) |
| 32 | if err != nil { |
| 33 | return nil, err |
| 34 | } |
| 35 | defer rows.Close() |
| 36 | |
| 37 | var workspaces []models.Workspace |
| 38 | for rows.Next() { |
| 39 | var w models.Workspace |
| 40 | var createdAt, updatedAt string |
| 41 | var lastItemActivity sql.NullString |
| 42 | if err := rows.Scan(&w.ID, &w.Name, &w.Slug, &w.OwnerID, &w.OwnerUsername, &w.Description, &w.Settings, &w.Source, &createdAt, &updatedAt, &lastItemActivity); err != nil { |
| 43 | return nil, err |
| 44 | } |
| 45 | w.CreatedAt = parseTime(createdAt) |
| 46 | w.UpdatedAt = effectiveWorkspaceUpdatedAt(updatedAt, lastItemActivity) |
| 47 | w.HydrateDerivedFields() |
| 48 | workspaces = append(workspaces, w) |
| 49 | } |
| 50 | return workspaces, rows.Err() |
| 51 | } |
| 52 | |
| 53 | // effectiveWorkspaceUpdatedAt returns the later of the workspace's own |
| 54 | // updated_at and the most recent item activity inside it. See BUG-1481 |
no test coverage detected