diff --git a/docs/content/2.concepts/1.how-it-works.md b/docs/content/2.concepts/1.how-it-works.md index 5c32c78..4bd8454 100644 --- a/docs/content/2.concepts/1.how-it-works.md +++ b/docs/content/2.concepts/1.how-it-works.md @@ -56,26 +56,16 @@ Sources should respect `cap` to keep memory bounded — `RelatedActivityLogSourc ## Type taxonomy -::callout{icon="i-lucide-alert-triangle" color="warning"} -**Two distinct "type" axes exist. Do not confuse them.** +The **entry-type** axis (`$entry->type`) and the **source-priority config** axis (`source_priorities` keys) align one-to-one: -The **entry-type** axis (`$entry->type`) has **3 values today**: +| Source | `$entry->type` | `source_priorities` key | +| -------------------------- | ---------------------- | ------------------------ | +| `ActivityLogSource` | `activity_log` | `activity_log` | +| `RelatedActivityLogSource` | `related_activity_log` | `related_activity_log` | +| `RelatedModelSource` | `related_model` | `related_model` | +| `CustomEventSource` | `custom` | `custom` | -- `activity_log` -- `related_model` -- `custom` - -The **source-priority config** axis (`source_priorities` config keys) has **4 keys**: - -- `activity_log` -- `related_activity_log` -- `related_model` -- `custom` - -Critically: RelatedActivityLogSource emits entries with `type='activity_log'` (**not** `'related_activity_log'`). Filtering with `->ofType(['related_activity_log'])` will never match anything. To distinguish own-log entries from related-log entries today, inspect `$entry->relatedModel` (it's `null` for `ActivityLogSource` entries and an Eloquent model for `RelatedActivityLogSource` entries) after calling `->get()` — there is no builder-level filter for source-of-origin. - -See [/troubleshooting](/troubleshooting) ("Type filter doesn't match anything") and [issue #11](https://github.com/relaticle/activity-log/issues/11). -:: +To match both spatie-log sources in a filter, pass both keys: `->ofType(['activity_log', 'related_activity_log'])`. The built-in `ActivityLogRenderer` is auto-registered for both types, so diff rendering works for own-log and related-log entries without extra wiring. ## Source priorities diff --git a/docs/content/3.essentials/1.sources.md b/docs/content/3.essentials/1.sources.md index c4ddf1f..7021977 100644 --- a/docs/content/3.essentials/1.sources.md +++ b/docs/content/3.essentials/1.sources.md @@ -53,7 +53,7 @@ For each named relation, the source loads the related rows, then queries `activi :: ::callout{icon="i-lucide-info" color="info"} -Entries from this source carry `type='activity_log'`, **not** `'related_activity_log'`. The `related_activity_log` key only exists in `config('activity-log.source_priorities')` for priority configuration. See the type taxonomy in [/concepts/how-it-works](/concepts/how-it-works#type-taxonomy). +Entries from this source carry `type='related_activity_log'` and dedup-collide with the matching `RelatedModelSource` event when both fire at the same second. The built-in `ActivityLogRenderer` is auto-registered for both `activity_log` and `related_activity_log`, so spatie diffs render automatically for related-model logs too. :: ## `fromRelation(string $relation, Closure $configure)` diff --git a/docs/content/3.essentials/2.filament-ui.md b/docs/content/3.essentials/2.filament-ui.md index bd7c22a..4f91085 100644 --- a/docs/content/3.essentials/2.filament-ui.md +++ b/docs/content/3.essentials/2.filament-ui.md @@ -146,7 +146,7 @@ Each filter mutates the underlying `Relaticle\ActivityLog\Timeline\TimelineBuild A `resetFilters()` Livewire action is wired to the clear button — it nulls all three properties and rewinds `visibleCount` to `perPage`. ::callout{icon="i-lucide-info" color="info"} -The `typeFilter` value is matched against `$entry->type`, so only the three real entry-type values resolve (`activity_log`, `related_model`, `custom`). Filtering by `'related_activity_log'` matches nothing — see the type taxonomy in [/concepts/how-it-works](/concepts/how-it-works#type-taxonomy). +The `typeFilter` value is matched against `$entry->type`. Built-in types: `activity_log`, `related_activity_log`, `related_model`, `custom`. See the type taxonomy in [/concepts/how-it-works](/concepts/how-it-works#type-taxonomy). :: For programmatic equivalents — pre-applying filters from PHP rather than the URL — see [/essentials/refining-the-timeline](/essentials/refining-the-timeline). diff --git a/docs/content/3.essentials/3.refining-the-timeline.md b/docs/content/3.essentials/3.refining-the-timeline.md index c855655..4826212 100644 --- a/docs/content/3.essentials/3.refining-the-timeline.md +++ b/docs/content/3.essentials/3.refining-the-timeline.md @@ -34,8 +34,8 @@ $record->timeline() Type and event filters are mirrored onto every source's `Window` so sources can push them into SQL where possible. The builder also re-applies them post-yield as a safety net, so a source that ignores the `Window` filters still produces correct output. -::callout{icon="i-lucide-alert-triangle" color="warning"} -**There are only three entry types today: `activity_log`, `related_model`, `custom`.** Entries from `RelatedActivityLogSource` carry `type='activity_log'` — calling `->ofType(['related_activity_log'])` will silently match nothing. See the [type taxonomy](/concepts/how-it-works#type-taxonomy) for the full breakdown. +::callout{icon="i-lucide-info" color="info"} +**Built-in entry types: `activity_log`, `related_activity_log`, `related_model`, `custom`.** `ActivityLogSource` emits `activity_log`; `RelatedActivityLogSource` emits `related_activity_log`. To match both spatie-log sources, pass both keys: `->ofType(['activity_log', 'related_activity_log'])`. See the [type taxonomy](/concepts/how-it-works#type-taxonomy). :: ## Sorting diff --git a/docs/content/3.essentials/6.configuration.md b/docs/content/3.essentials/6.configuration.md index 3238580..93ed3ef 100644 --- a/docs/content/3.essentials/6.configuration.md +++ b/docs/content/3.essentials/6.configuration.md @@ -18,7 +18,7 @@ Every knob the package exposes lives in `config/activity-log.php`. Publish it wi | `pagination_buffer` | `int` | `2` | Per-source over-fetch multiplier: `cap = perPage × (page + buffer)`. See [/essentials/refining-the-timeline#pagination-buffer-mechanics](/essentials/refining-the-timeline#pagination-buffer-mechanics). | | `deduplicate_by_default` | `bool` | `true` | Builder dedup default; overridable per-call via `->deduplicate(false)`. | | `source_priorities.activity_log` | `int` | `10` | Priority for `ActivityLogSource`. | -| `source_priorities.related_activity_log` | `int` | `10` | Priority for `RelatedActivityLogSource`. **Note**: priority key only — entries from this source carry `type='activity_log'`, NOT `'related_activity_log'`. See [/concepts/how-it-works#type-taxonomy](/concepts/how-it-works#type-taxonomy). | +| `source_priorities.related_activity_log` | `int` | `10` | Priority for `RelatedActivityLogSource`. Entries from this source carry `type='related_activity_log'`. | | `source_priorities.related_model` | `int` | `20` | Priority for `RelatedModelSource`. | | `source_priorities.custom` | `int` | `30` | Priority for `CustomEventSource`. | | `renderers` | `array` | `[]` | Event-or-type → renderer map. See [/essentials/customization#registration-channels](/essentials/customization#registration-channels). | diff --git a/docs/content/6.troubleshooting/1.index.md b/docs/content/6.troubleshooting/1.index.md index e4972b6..e5256dc 100644 --- a/docs/content/6.troubleshooting/1.index.md +++ b/docs/content/6.troubleshooting/1.index.md @@ -22,13 +22,14 @@ Renderers resolve in this order: explicit `$entry->renderer` → `bindings[$entr Dedup uses `dedupKey` + `sourcePriority`. If two sources emit the same logical event with different keys, they won't collapse. Either align `dedupKey` on both sources (use `->dedupKeyUsing()` on the builder) or raise the preferred source's priority so the loser is dropped. Mechanics at [/concepts/how-it-works#dedup-behavior](/concepts/how-it-works#dedup-behavior). -## Type filter doesn't match anything +## Cache invalidation flushed unrelated caches ::callout{icon="i-lucide-alert-triangle" color="warning"} -- **Symptom:** `$record->timeline()->fromActivityLogOf(['emails'])->ofType(['related_activity_log'])->get()` returns empty. -- **Cause:** `RelatedActivityLogSource` emits entries with `type='activity_log'` (NOT `'related_activity_log'`). The `related_activity_log` key only exists in `source_priorities` config — for priority configuration only. -- **Workaround:** filter with `->ofType(['activity_log'])` to include both own- and related-log entries. To distinguish them at the entry level, inspect `$entry->relatedModel` (`null` for `ActivityLogSource`, an Eloquent model for `RelatedActivityLogSource`). -- **Tracking:** [issue #11](https://github.com/relaticle/activity-log/issues/11). +- **Symptom:** after calling `$record->forgetTimelineCache()`, sessions / queue locks / application caches are gone too. +- **Cause:** `TimelineCache::forget()` calls `Cache::store(...)->getStore()->flush()` — flushes the entire cache store, not just this subject's keys. +- **Workaround:** configure `cache.store` to a dedicated Laravel cache store used only by the timeline. Or skip explicit invalidation and let TTL expire naturally (set a short `->cached($ttl)`). +- **Tracking:** [issue #12](https://github.com/relaticle/activity-log/issues/12). +- Full caveat at [/essentials/caching#invalidation--known-limitation](/essentials/caching#invalidation--known-limitation). :: ## `fromActivityLog()` throws on a fresh model diff --git a/src/ActivityLogServiceProvider.php b/src/ActivityLogServiceProvider.php index d7a7c77..1346f08 100644 --- a/src/ActivityLogServiceProvider.php +++ b/src/ActivityLogServiceProvider.php @@ -31,7 +31,8 @@ public function packageBooted(): void { Livewire::component('activity-log', Filament\Livewire\ActivityLogLivewire::class); - $this->app->make(RendererRegistry::class) - ->register('activity_log', Renderers\ActivityLogRenderer::class); + $registry = $this->app->make(RendererRegistry::class); + $registry->register('activity_log', Renderers\ActivityLogRenderer::class); + $registry->register('related_activity_log', Renderers\ActivityLogRenderer::class); } } diff --git a/src/Timeline/Sources/RelatedActivityLogSource.php b/src/Timeline/Sources/RelatedActivityLogSource.php index 98950ea..9ecd593 100644 --- a/src/Timeline/Sources/RelatedActivityLogSource.php +++ b/src/Timeline/Sources/RelatedActivityLogSource.php @@ -82,7 +82,7 @@ private function makeEntry(Model $subject, ActivityModel $activity, Model $relat return new TimelineEntry( id: sprintf('related_activity_log:%s:%s', $activity->id, $event), - type: 'activity_log', + type: 'related_activity_log', event: $event, occurredAt: $occurredAt, dedupKey: $this->dedupKeyFor($relatedModel::class, (string) $relatedModel->getKey(), $occurredAt), diff --git a/tests/Feature/BuilderDedupTest.php b/tests/Feature/BuilderDedupTest.php index 620d39f..45eb5e8 100644 --- a/tests/Feature/BuilderDedupTest.php +++ b/tests/Feature/BuilderDedupTest.php @@ -46,7 +46,7 @@ ->get(); expect($entries)->toHaveCount(1) - ->and($entries->first()->type)->toBe('activity_log'); + ->and($entries->first()->type)->toBe('related_activity_log'); }); it('dedupKeyUsing() overrides the per-entry dedup key', function (): void {