mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-25 11:52:08 +00:00
fix: enrich activity log entries with item titles and collection info (#1)
The activity list endpoint returned raw entries without item context, causing the activity page to show bare "Created"/"Updated" verbs. The dashboard already enriched entries via GetItem() lookups — now the activity handler does the same, and the frontend reads top-level fields with metadata fallback.
This commit is contained in:
@@ -16,6 +16,11 @@ type Activity struct {
|
||||
Source string `json:"source"`
|
||||
Metadata string `json:"metadata,omitempty"` // JSON
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// Enrichment fields — populated by handlers, not stored in DB
|
||||
ItemTitle string `json:"item_title,omitempty"`
|
||||
ItemSlug string `json:"item_slug,omitempty"`
|
||||
CollectionSlug string `json:"collection_slug,omitempty"`
|
||||
}
|
||||
|
||||
type ActivityListParams struct {
|
||||
|
||||
@@ -39,6 +39,9 @@ func (s *Server) handleListWorkspaceActivity(w http.ResponseWriter, r *http.Requ
|
||||
activities = []models.Activity{}
|
||||
}
|
||||
|
||||
// Enrich activities with item titles and collection info
|
||||
s.enrichActivities(activities)
|
||||
|
||||
writeJSON(w, http.StatusOK, activities)
|
||||
}
|
||||
|
||||
@@ -73,5 +76,25 @@ func (s *Server) handleListDocumentActivity(w http.ResponseWriter, r *http.Reque
|
||||
activities = []models.Activity{}
|
||||
}
|
||||
|
||||
// Enrich activities with item titles and collection info
|
||||
s.enrichActivities(activities)
|
||||
|
||||
writeJSON(w, http.StatusOK, activities)
|
||||
}
|
||||
|
||||
// enrichActivities populates ItemTitle, ItemSlug, and CollectionSlug
|
||||
// on each activity by looking up the referenced item.
|
||||
func (s *Server) enrichActivities(activities []models.Activity) {
|
||||
for i := range activities {
|
||||
if activities[i].DocumentID == "" {
|
||||
continue
|
||||
}
|
||||
item, err := s.store.GetItem(activities[i].DocumentID)
|
||||
if err != nil || item == nil {
|
||||
continue
|
||||
}
|
||||
activities[i].ItemTitle = item.Title
|
||||
activities[i].ItemSlug = item.Slug
|
||||
activities[i].CollectionSlug = item.CollectionSlug
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +238,9 @@ export interface Activity {
|
||||
source: string;
|
||||
metadata: string;
|
||||
created_at: string;
|
||||
item_title?: string;
|
||||
item_slug?: string;
|
||||
collection_slug?: string;
|
||||
}
|
||||
|
||||
// ─── Dashboard ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -88,10 +88,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Client-side collection filter (metadata contains item_collection info)
|
||||
// Client-side collection filter using enriched top-level field or metadata fallback
|
||||
let filteredActivities = $derived.by(() => {
|
||||
if (!filterCollection) return activities;
|
||||
return activities.filter((a) => {
|
||||
if (a.collection_slug) return a.collection_slug === filterCollection;
|
||||
try {
|
||||
const meta = JSON.parse(a.metadata);
|
||||
return meta.collection_slug === filterCollection || meta.collection === filterCollection;
|
||||
@@ -299,6 +300,9 @@
|
||||
<div class="date-entries">
|
||||
{#each group.items as activity (activity.id)}
|
||||
{@const meta = parseMeta(activity.metadata)}
|
||||
{@const itemTitle = activity.item_title || meta.item_title || meta.title}
|
||||
{@const itemSlug = activity.item_slug || meta.item_slug}
|
||||
{@const collSlug = activity.collection_slug || meta.collection_slug}
|
||||
{@const src = getSourceLabel(activity.source, activity.actor)}
|
||||
<div class="entry {borderClass(activity.source, activity.actor)}">
|
||||
<span
|
||||
@@ -310,18 +314,16 @@
|
||||
<div class="entry-content">
|
||||
<div class="entry-main">
|
||||
<span class="entry-verb">{activityVerb(activity.action)}</span>
|
||||
{#if meta.item_title && meta.item_slug && meta.collection_slug}
|
||||
{#if itemTitle && itemSlug && collSlug}
|
||||
<a
|
||||
href="/{wsSlug}/{meta.collection_slug}/{meta.item_slug}"
|
||||
class="entry-item-link">{meta.item_title}</a
|
||||
href="/{wsSlug}/{collSlug}/{itemSlug}"
|
||||
class="entry-item-link">{itemTitle}</a
|
||||
>
|
||||
{:else if meta.item_title}
|
||||
<span class="entry-item-name">{meta.item_title}</span>
|
||||
{:else if meta.title}
|
||||
<span class="entry-item-name">{meta.title}</span>
|
||||
{:else if itemTitle}
|
||||
<span class="entry-item-name">{itemTitle}</span>
|
||||
{/if}
|
||||
{#if meta.collection_slug}
|
||||
<span class="entry-collection">{meta.collection_slug}</span>
|
||||
{#if collSlug}
|
||||
<span class="entry-collection">{collSlug}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if meta.changes}
|
||||
|
||||
Reference in New Issue
Block a user