better rum todo
Build and Publish / Metadata (push) Successful in 10s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 1m53s

This commit is contained in:
mats committed 2026-09-22 09:15:00 +02:00
1 parent cb3266bf33
commit e81b8c2fcd
6 files changed
+231 -51

No files matched your search

+22 -18
View File
@@ -31,14 +31,16 @@ func clipTo(s string, n int) string {
}
type todoPayload struct {
Project string `json:"project"`
Text string `json:"text"`
Component string `json:"component"`
Path string `json:"path"`
Hash string `json:"hash"`
URL string `json:"url"`
UserAgent string `json:"ua"`
Session string `json:"session"`
Project string `json:"project"`
Text string `json:"text"`
Component string `json:"component"`
Path string `json:"path"`
Hash string `json:"hash"`
URL string `json:"url"`
UserAgent string `json:"ua"`
Session string `json:"session"`
ElementSelector string `json:"elementSelector"`
ElementLabel string `json:"elementLabel"`
}
// HandleTodoCreate ingests a todo posted by otel-todo.js. It is guarded by
@@ -72,16 +74,18 @@ func (c *Collector) HandleTodoCreate(w http.ResponseWriter, r *http.Request) {
id := make([]byte, 8)
_, _ = rand.Read(id)
t := todos.Todo{
ID: hex.EncodeToString(id),
Project: project,
Text: text,
Component: clipTo(p.Component, maxTodoMeta),
Path: clipTo(p.Path, maxTodoMeta),
Hash: clipTo(p.Hash, maxTodoMeta),
URL: clipTo(p.URL, maxTodoMeta),
UserAgent: clipTo(p.UserAgent, maxTodoMeta),
Session: clipTo(p.Session, maxTodoMeta),
CreatedAt: time.Now().UTC(),
ID: hex.EncodeToString(id),
Project: project,
Text: text,
Component: clipTo(p.Component, maxTodoMeta),
Path: clipTo(p.Path, maxTodoMeta),
Hash: clipTo(p.Hash, maxTodoMeta),
URL: clipTo(p.URL, maxTodoMeta),
UserAgent: clipTo(p.UserAgent, maxTodoMeta),
Session: clipTo(p.Session, maxTodoMeta),
ElementSelector: clipTo(p.ElementSelector, maxTodoMeta),
ElementLabel: clipTo(p.ElementLabel, maxTodoMeta),
CreatedAt: time.Now().UTC(),
}
if err := c.todoStore.Add(r.Context(), t); err != nil {
log.Printf("failed to store todo: %v", err)
+19 -17
View File
@@ -17,18 +17,20 @@ import (
// Todo is one note filed from a page. Project is the RUM service name.
type Todo struct {
ID string `json:"id"`
Project string `json:"project"`
Text string `json:"text"`
Component string `json:"component,omitempty"`
Path string `json:"path,omitempty"`
Hash string `json:"hash,omitempty"`
URL string `json:"url,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
Session string `json:"session,omitempty"`
CreatedAt time.Time `json:"createdAt"`
Done bool `json:"done"`
DoneAt time.Time `json:"doneAt,omitzero"`
ID string `json:"id"`
Project string `json:"project"`
Text string `json:"text"`
Component string `json:"component,omitempty"`
Path string `json:"path,omitempty"`
Hash string `json:"hash,omitempty"`
URL string `json:"url,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
Session string `json:"session,omitempty"`
ElementSelector string `json:"elementSelector,omitempty"` // CSS selector of the referenced element, if picked
ElementLabel string `json:"elementLabel,omitempty"` // human-readable tag/text summary of that element
CreatedAt time.Time `json:"createdAt"`
Done bool `json:"done"`
DoneAt time.Time `json:"doneAt,omitzero"`
}
// Store persists todos. List returns newest first; an empty project means all.
@@ -154,7 +156,7 @@ func NewClickHouseStore(ctx context.Context, conn driver.Conn, db string) (*Clic
if err != nil {
return nil, err
}
for _, col := range []string{"done UInt8", "done_at DateTime64(3, 'UTC')"} {
for _, col := range []string{"done UInt8", "done_at DateTime64(3, 'UTC')", "element_selector String", "element_label String"} {
if err := conn.Exec(ctx, fmt.Sprintf(`ALTER TABLE %s.todos ADD COLUMN IF NOT EXISTS %s`, db, col)); err != nil {
return nil, err
}
@@ -163,12 +165,12 @@ func NewClickHouseStore(ctx context.Context, conn driver.Conn, db string) (*Clic
}
func (s *ClickHouseStore) Add(ctx context.Context, t Todo) error {
return s.conn.Exec(ctx, fmt.Sprintf(`INSERT INTO %s.todos (id, project, text, component, path, hash, url, user_agent, session, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, s.db),
t.ID, t.Project, t.Text, t.Component, t.Path, t.Hash, t.URL, t.UserAgent, t.Session, t.CreatedAt.UTC())
return s.conn.Exec(ctx, fmt.Sprintf(`INSERT INTO %s.todos (id, project, text, component, path, hash, url, user_agent, session, element_selector, element_label, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, s.db),
t.ID, t.Project, t.Text, t.Component, t.Path, t.Hash, t.URL, t.UserAgent, t.Session, t.ElementSelector, t.ElementLabel, t.CreatedAt.UTC())
}
func (s *ClickHouseStore) List(ctx context.Context, project string, limit int) ([]Todo, error) {
q := fmt.Sprintf(`SELECT id, project, text, component, path, hash, url, user_agent, session, created_at, done, done_at FROM %s.todos`, s.db)
q := fmt.Sprintf(`SELECT id, project, text, component, path, hash, url, user_agent, session, element_selector, element_label, created_at, done, done_at FROM %s.todos`, s.db)
var args []any
if project != "" {
q += ` WHERE project = ?`
@@ -185,7 +187,7 @@ func (s *ClickHouseStore) List(ctx context.Context, project string, limit int) (
for rows.Next() {
var t Todo
var done uint8
if err := rows.Scan(&t.ID, &t.Project, &t.Text, &t.Component, &t.Path, &t.Hash, &t.URL, &t.UserAgent, &t.Session, &t.CreatedAt, &done, &t.DoneAt); err != nil {
if err := rows.Scan(&t.ID, &t.Project, &t.Text, &t.Component, &t.Path, &t.Hash, &t.URL, &t.UserAgent, &t.Session, &t.ElementSelector, &t.ElementLabel, &t.CreatedAt, &done, &t.DoneAt); err != nil {
return nil, err
}
t.Done = done != 0