Skip to content

Adding Event History to Detail Pages

Audience: frontend developers wiring event history into pages. See also: Event History Viewer (Backend) for the query/handler implementation, and Event History Viewer: How It Works for the end-user view.

This guide shows how to add event history viewing capabilities to any aggregate detail page in Foundry.

Quick Start

For most detail pages, use the side panel pattern - it provides the best UX without cluttering the main page.

1. Import the Component

<script lang="ts">
    import EventHistorySidePanel from '$lib/components/events/event-history-side-panel.svelte';
    import { History } from '@lucide/svelte';
</script>

2. Add State Variable

<script lang="ts">
    // Your existing state
    let myAggregate: MyAggregate | null = $state(null);

    // Add this for event history
    let showEventHistory = $state(false);
</script>

3. Add Button to Page Header

Add the button near your existing action buttons (usually near Edit, Delete, etc.):

<div class="flex gap-2">
    <!-- Your existing buttons -->
    <Button variant="outline" size="sm" onclick={() => showEventHistory = true} disabled={!myAggregate}>
        <History class="mr-2 h-4 w-4" />
        Event History
    </Button>
    <Button size="sm" onclick={startEdit}>
        <Edit class="mr-2 h-4 w-4" />
        Edit
    </Button>
</div>

4. Add Side Panel at End of Page

Place this after your main content, before the closing </div>:

<!-- Event History Side Panel -->
{#if myAggregate}
    <EventHistorySidePanel
        aggregateRootId={myAggregate.id}
        title="My Aggregate Event History"
        bind:open={showEventHistory}
    />
{/if}

Complete Example

Here's a complete example based on a participant detail page:

<script lang="ts">
    import { onMount } from 'svelte';
    import { page } from '$app/stores';
    import { goto } from '$app/navigation';
    import { getParticipantById, type Participant } from '$lib/utils/query-helpers';
    import * as Card from '$lib/components/ui/card';
    import { Button } from '$lib/components/ui/button';
    import { ChevronLeft, Edit, History } from '@lucide/svelte';
    import EventHistorySidePanel from '$lib/components/events/event-history-side-panel.svelte';

    const participantId = $derived($page.params.id!);

    let participant = $state<Participant | null>(null);
    let isLoading = $state(true);
    let error = $state<string | null>(null);
    let showEventHistory = $state(false);

    onMount(async () => {
        await loadParticipant();
    });

    async function loadParticipant() {
        try {
            isLoading = true;
            error = null;
            const response = await getParticipantById(participantId);
            if (response.data) {
                participant = response.data;
            } else {
                error = 'Participant not found';
            }
        } catch (err: any) {
            error = err.message;
        } finally {
            isLoading = false;
        }
    }

    function goBack() {
        goto('/participants');
    }
</script>

<svelte:head>
    <title>{participant?.name || 'Participant'} - Foundry</title>
</svelte:head>

<div class="space-y-6">
    <!-- Page Header -->
    <div class="flex items-center justify-between">
        <div class="flex items-center gap-4">
            <Button variant="ghost" size="icon" onclick={goBack}>
                <ChevronLeft class="h-5 w-5" />
            </Button>
            <h2 class="text-3xl font-bold">{participant?.name || 'Participant'}</h2>
        </div>
        <div class="flex gap-2">
            <Button
                variant="outline"
                size="sm"
                onclick={() => showEventHistory = true}
                disabled={!participant}
            >
                <History class="mr-2 h-4 w-4" />
                Event History
            </Button>
            <Button size="sm" disabled={!participant}>
                <Edit class="mr-2 h-4 w-4" />
                Edit
            </Button>
        </div>
    </div>

    <!-- Main Content -->
    {#if isLoading}
        <div class="flex h-64 items-center justify-center">
            <p>Loading...</p>
        </div>
    {:else if participant}
        <Card.Root>
            <Card.Header>
                <Card.Title>Participant Details</Card.Title>
            </Card.Header>
            <Card.Content>
                <!-- Your participant details here -->
            </Card.Content>
        </Card.Root>
    {/if}
</div>

<!-- Event History Side Panel -->
{#if participant}
    <EventHistorySidePanel
        aggregateRootId={participant.id}
        title="Participant Event History"
        bind:open={showEventHistory}
    />
{/if}

Alternative: Tabs Pattern

If you prefer showing event history as a permanent tab rather than a button:

<script lang="ts">
    import EventHistoryPanel from '$lib/components/events/event-history-panel.svelte';
    import * as Tabs from '$lib/components/ui/tabs';

    let participant: Participant | null = $state(null);
</script>

<Tabs.Root value="details">
    <Tabs.List>
        <Tabs.Trigger value="details">Details</Tabs.Trigger>
        <Tabs.Trigger value="events">Event History</Tabs.Trigger>
    </Tabs.List>

    <Tabs.Content value="details">
        <!-- Your detail content -->
    </Tabs.Content>

    <Tabs.Content value="events">
        {#if participant?.id}
            <EventHistoryPanel
                aggregateRootId={participant.id}
                title="Participant Events"
            />
        {/if}
    </Tabs.Content>
</Tabs.Root>

Pages to Add Event History

Consider adding event history to these aggregate detail pages:

  • Competitions - Already implemented
  • [ ] Teams - src/Apps/foundry-web/src/routes/teams/[id]/+page.svelte
  • [ ] Participants - src/Apps/foundry-web/src/routes/participants/[id]/+page.svelte
  • [ ] Sporting Events (Fixtures) - src/Apps/foundry-web/src/routes/fixtures/[id]/+page.svelte
  • [ ] Users - src/Apps/foundry-web/src/routes/admin/users/[id]/+page.svelte

Checklist

When adding event history to a page:

  • [ ] Import EventHistorySidePanel component
  • [ ] Import History icon from @lucide/svelte
  • [ ] Add showEventHistory state variable
  • [ ] Add "Event History" button to page header
  • [ ] Add side panel component at end of page
  • [ ] Test opening/closing the panel
  • [ ] Test with an aggregate that has events
  • [ ] Test search functionality
  • [ ] Test download functionality

Tips

  1. Button Placement: Place the "Event History" button near other action buttons, typically before the primary action (Edit)
  2. Disabled State: Disable the button when the aggregate hasn't loaded yet
  3. Title: Customize the title to match the aggregate type (e.g., "Competition Event History", "Team Event History")
  4. Testing: To test, create/update the aggregate and verify events appear in the history panel