Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,9 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
cache-dependency-path: listener/package-lock.json
- name: Install dependencies
working-directory: listener
run: npm ci
run: npm install
- name: Run lint
working-directory: listener
run: npm run lint
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/ActivityFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export function ActivityFeed() {

// Clear stale activity and re-fetch from page 1 whenever the connected
// wallet address changes (switch or disconnect). This is the fix for issue #175.
useWalletAccountSync((_nextAddress) => {
useWalletAccountSync(() => {
setEvents([]);
setLiveEvents([]);
setTotal(0);
Expand Down
5 changes: 3 additions & 2 deletions dashboard/src/components/EventExplorerCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ function shortenAddress(address: string) {
if (address.length <= 14) {
return address;
}

return `${address.slice(0, 6)}...${address.slice(-4)}`;
}

Expand All @@ -34,7 +33,7 @@ interface EventExplorerCardProps {
event: BlockchainEvent;
onCopyContract: (contractAddress: string) => void;
isCopied: boolean;
contractStatuses: ContractStatus[];
contractStatuses?: ContractStatus[];
}

export function EventExplorerCard({
Expand All @@ -48,6 +47,8 @@ export function EventExplorerCard({
const label = event.eventName ?? event.type;
const badgeClass = getEventKindClass(event.type);
const kindLabel = getEventKindLabel(event.type);
const contractStatus = contractStatuses.find(c => c.address === event.contractAddress);
const isPaused = contractStatus?.paused ?? false;

return (
<article className="event-explorer__row" role="row" data-event-id={event.eventId}>
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/EventExplorerTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { EventExplorerCard } from './EventExplorerCard';

interface EventExplorerTableProps {
events: BlockchainEvent[];
contractStatuses: ContractStatus[];
contractStatuses?: ContractStatus[];
}

export function EventExplorerTable({ events, contractStatuses }: EventExplorerTableProps) {
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/pages/EventExplorerPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function EventExplorerPage() {

// Clear stale events and re-fetch whenever the connected wallet address
// changes (switch or disconnect). This is the fix for issue #175.
useWalletAccountSync((_nextAddress) => {
useWalletAccountSync(() => {
setEvents([]);
setError(null);
setPage(1);
Expand Down
19 changes: 12 additions & 7 deletions dashboard/src/store/eventStore.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ import { EventList } from '../components/EventList';
import { useEventStore } from '../store/eventStore';
import { generateMockEvents } from '../utils/eventData';

const BLANK_FILTERS = {
search: '',
contractAddress: 'all',
eventType: 'all',
status: 'all' as const,
dateFrom: '',
dateTo: '',
};

describe('event store selective subscriptions', () => {
it('deduplicates events before rendering notification rows', () => {
const [firstEvent, secondEvent] = generateMockEvents(2);
Expand Down Expand Up @@ -42,7 +51,7 @@ describe('event store selective subscriptions', () => {
it('filter updates do not require reloading the full event collection', async () => {
useEventStore.setState({
events: generateMockEvents(100),
filters: { search: '', contractAddress: 'all', eventType: 'all', status: 'all', dateFrom: '', dateTo: '' },
filters: BLANK_FILTERS,
isLoading: false,
error: null,
});
Expand Down Expand Up @@ -70,30 +79,26 @@ describe('pagination + filter interaction', () => {
const events = generateMockEvents(200);
useEventStore.setState({
events,
filters: { search: '', contractAddress: 'all', eventType: 'all', status: 'all', dateFrom: '', dateTo: '' },
filters: BLANK_FILTERS,
isLoading: false,
error: null,
});

// Render just the list with a large scroll offset to simulate being deep in the list
const { rerender } = render(<EventList events={events} />);
expect(screen.getAllByRole('listitem').length).toBeGreaterThan(0);

// Now simulate a filter being applied — pass a small filtered result
// while the internal scrollTop state is still set to a large value
const filtered = events.filter((e) => e.eventName === 'TaskCreated');
act(() => {
rerender(<EventList events={filtered} />);
});

// The list must still render rows — not go blank
expect(screen.getAllByRole('listitem').length).toBeGreaterThan(0);
});

it('filter change resets scroll position to top', async () => {
useEventStore.setState({
events: generateMockEvents(100),
filters: { search: '', contractAddress: 'all', eventType: 'all', status: 'all', dateFrom: '', dateTo: '' },
filters: BLANK_FILTERS,
isLoading: false,
error: null,
});
Expand Down
Loading
Loading