account page: fixed platform reordering bugs

This commit is contained in:
2026-01-28 02:14:27 -07:00
parent a50c0ef18d
commit 8f38f141e5
8 changed files with 141 additions and 72 deletions
+19 -9
View File
@@ -12,10 +12,15 @@ import (
)
// TODO: simpify, if possible (single query ideal)
func (db *Store) SetOrderOfPlatformOnAccountPage(ctx context.Context, acctID int64, platform Platform, orderIndex int) error {
func (db *Store) SetOrderOfPlatformOnAccountPage(
ctx context.Context,
acctID int64,
platform Platform,
orderIndex int,
) (orderedPlatforms []Platform, prevOrderIndex int, err error) {
tx, err := db.db.Begin(ctx)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
return nil, 0, fmt.Errorf("failed to start transaction: %w", err)
}
defer tx.Rollback(ctx)
@@ -39,7 +44,7 @@ func (db *Store) SetOrderOfPlatformOnAccountPage(ctx context.Context, acctID int
},
)
if err != nil {
return fmt.Errorf("failed to perform query to look up existing indexes: %w", err)
return nil, 0, fmt.Errorf("failed to perform query to look up existing indexes: %w", err)
}
indexes, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[struct {
@@ -47,7 +52,7 @@ func (db *Store) SetOrderOfPlatformOnAccountPage(ctx context.Context, acctID int
Order_index int
}])
if err != nil {
return fmt.Errorf("failed to scan rows for query to look up existing indexes: %w", err)
return nil, 0, fmt.Errorf("failed to scan rows for query to look up existing indexes: %w", err)
}
// compute the implied indexes,
@@ -74,9 +79,13 @@ func (db *Store) SetOrderOfPlatformOnAccountPage(ctx context.Context, acctID int
}
}
prevOrderIndex := indexPerPlatform[platform]
prevOrderIndex = indexPerPlatform[platform]
orderedPlatforms = make([]Platform, len(allPlatforms))
if indexPerPlatform[platform] == orderIndex {
return nil
for i := range allPlatforms {
orderedPlatforms[i] = platformPerIndex[i]
}
return orderedPlatforms, prevOrderIndex, nil
}
if increased := orderIndex > prevOrderIndex; increased {
@@ -110,6 +119,7 @@ func (db *Store) SetOrderOfPlatformOnAccountPage(ctx context.Context, acctID int
valuesLines[i] = fmt.Sprintf("(@account_id, @platform_%d, @order_index_%d::smallint)", i, i)
args[fmt.Sprintf("platform_%d", i)] = p
args[fmt.Sprintf("order_index_%d", i)] = indexPerPlatform[p]
orderedPlatforms[i] = platformPerIndex[i]
}
_, err = tx.Exec(
@@ -148,14 +158,14 @@ func (db *Store) SetOrderOfPlatformOnAccountPage(ctx context.Context, acctID int
args,
)
if err != nil {
return fmt.Errorf("failed to perform query to delete old indexes and insert new indexes: %w", err)
return nil, 0, fmt.Errorf("failed to perform query to delete old indexes and insert new indexes: %w", err)
}
if tx.Commit(ctx); err != nil {
return fmt.Errorf("failed to commit txn: %w", err)
return nil, 0, fmt.Errorf("failed to commit txn: %w", err)
}
return nil
return orderedPlatforms, prevOrderIndex, nil
}
func (db *Store) GetOrderOfPlatformsOnAccountPage(ctx context.Context, acctID int64) ([]Platform, error) {
@@ -51,7 +51,7 @@ func (v_ctx *StoreWithContext) GetAccountPointerByUserID(userID string) (*Accoun
return v_ctx.Store.GetAccountPointerByUserID(v_ctx.ctx, userID)
}
func (v_ctx *StoreWithContext) SetOrderOfPlatformOnAccountPage(acctID int64, platform Platform, orderIndex int) error {
func (v_ctx *StoreWithContext) SetOrderOfPlatformOnAccountPage(acctID int64, platform Platform, orderIndex int) ([]Platform, int, error) {
return v_ctx.Store.SetOrderOfPlatformOnAccountPage(v_ctx.ctx, acctID, platform, orderIndex)
}
+34 -2
View File
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
@@ -19,6 +20,7 @@ import (
type accountSubrouter struct {
log *logging.Logger
accts *accounts.Store
pub *sse.UpdateNotificationPublisher
}
func Routes(
@@ -30,6 +32,7 @@ func Routes(
as := &accountSubrouter{
log: logger,
accts: accts,
pub: pub,
}
r.POST("", response.Handler(as.createAccount))
@@ -187,9 +190,13 @@ func getOrderIndexForSyncGroupListingDraftFromPath(c *gin.Context) (int, error)
return orderIndex, nil
}
// PUT /:acctID/platforms/:platform/order-index"
// this endpoint is called when dragging a platform tab in the accounts page.
func (s *accountSubrouter) setOrderOfPlatformOnAccountPage(c *gin.Context) (response.Response, error) {
acctID := auth.GetIdentity(c).Account.AccountID
// validate parameters
var orderIndex int
if v, ok := c.GetPostForm("order-index"); !ok {
return nil, response.BadRequest().
@@ -216,9 +223,34 @@ func (s *accountSubrouter) setOrderOfPlatformOnAccountPage(c *gin.Context) (resp
platform = p
}
if err := s.accts.SetOrderOfPlatformOnAccountPage(c, acctID, platform, orderIndex); err != nil {
// update the order
platforms, prevIndex, err := s.accts.SetOrderOfPlatformOnAccountPage(c, acctID, platform, orderIndex)
if err != nil {
return nil, fmt.Errorf("failed to save record: %w", err)
}
return response.Status(200), nil
// emit events on all platforms updated, so the tabs can all refresh (including their logic)
platformEvents := make([]string, max(orderIndex, prevIndex)-min(orderIndex, prevIndex))
if orderIndex > prevIndex {
for i := range orderIndex - prevIndex {
p := platforms[prevIndex+i]
platformEvents[i] = fmt.Sprintf("accounts_%d_platforms_%s_order-index", acctID, lowerSnakeCase(p))
}
} else if orderIndex < prevIndex {
for i := range prevIndex - orderIndex {
p := platforms[orderIndex+1+i]
platformEvents[i] = fmt.Sprintf("accounts_%d_platforms_%s_order-index", acctID, lowerSnakeCase(p))
}
}
if err := s.pub.Push(c, acctID, platformEvents...); err != nil {
s.log.Errorf("failed to publish platform order-index events: %v", err)
}
return response.StatusNoContent(), nil
}
func lowerSnakeCase(s accounts.Platform) string {
return strings.ToLower(strings.Join(strings.Split(string(s), " "), "_"))
}
+30
View File
@@ -2,9 +2,11 @@ package sse
import (
"context"
"errors"
"fmt"
"path"
"strings"
"sync"
"time"
"github.com/gin-gonic/gin"
@@ -120,6 +122,34 @@ func (p *UpdateNotificationPublisher) Publish(pathPattern string) gin.HandlerFun
}
}
func (p *UpdateNotificationPublisher) Push(ctx context.Context, acctID int64, eventTypes ...string) error {
var wg sync.WaitGroup
wg.Add(len(eventTypes))
errs := make([]error, len(eventTypes))
for i, e := range eventTypes {
i := i
e := e
go func() {
defer wg.Done()
if err := p.queue.Send(ctx, Event{
AccountID: acctID,
Type: e,
Data: []byte(fmt.Sprintf(`{"eventType": %q}`, e)),
}); err != nil {
errs[i] = fmt.Errorf("failed to send sse event to listener: %w", err)
}
}()
}
wg.Wait()
return errors.Join(errs...)
return nil
}
func getPathSegments(p string) []string {
p = path.Clean(p)
if p == "" || p == "." || p == "/" {
+1 -1
View File
@@ -66,7 +66,7 @@ func Routes(
},
// strings
"lowerCamelCase": func(s string) string {
"lowerSnakeCase": func(s string) string {
return strings.ToLower(strings.Join(strings.Split(s, " "), "_"))
},