The History Plugin tracks a complete history of all operations performed on the desk with timestamps. It's perfect for audit trails, debugging, operation monitoring, and analytics.
import { useCheckIn } from 'vue-airport';
import { createHistoryPlugin } from '@vue-airport/plugins-base';
const { createDesk } = useCheckIn();
const { desk } = createDesk('items', {
plugins: [
createHistoryPlugin({ maxHistory: 100 })
]
});
maxHistory: numberMaximum number of history entries to keep. Default: 50.
createHistoryPlugin({
maxHistory: 100 // Keep last 100 operations
})
When the limit is reached, the oldest entries are automatically removed as new ones are added (FIFO - First In, First Out).
const { desk } = createDesk('items', {
plugins: [createHistoryPlugin({ maxHistory: 50 })]
});
// Perform operations
desk.checkIn('item-1', { name: 'First item' });
desk.checkIn('item-2', { name: 'Second item' });
desk.update('item-1', { name: 'Updated first item' });
desk.checkOut('item-2');
// Get full history
const history = desk.getHistory();
console.log(history);
// [
// { action: 'check-in', id: 'item-1', data: { name: 'First item' }, timestamp: 1700000001 },
// { action: 'check-in', id: 'item-2', data: { name: 'Second item' }, timestamp: 1700000002 },
// { action: 'update', id: 'item-1', data: { name: 'Updated first item' }, timestamp: 1700000003 },
// { action: 'check-out', id: 'item-2', timestamp: 1700000004 }
// ]
interface HistoryEntry<T> {
/** Type of operation performed */
action: 'check-in' | 'check-out' | 'update';
/** ID of the item involved */
id: string | number;
/** Data associated with the operation (not present for check-out) */
data?: T;
/** Timestamp when the operation occurred */
timestamp: number;
}
const history = desk.getHistory();
history.forEach(entry => {
console.log(`${entry.action} on ${entry.id} at ${new Date(entry.timestamp)}`);
});
// Get last 10 operations
const recent = desk.getLastHistory(10);
// Get last operation
const lastOp = desk.getLastHistory(1)[0];
console.log('Last operation:', lastOp.action);
// Get all check-ins
const checkIns = desk.getHistoryByAction('check-in');
// Get all updates
const updates = desk.getHistoryByAction('update');
// Get all check-outs
const checkOuts = desk.getHistoryByAction('check-out');
The history is stored in a reactive ref, so you can use it directly in computed properties:
const historyCount = computed(() => desk.history.value.length);
const latestEntry = computed(() => {
const history = desk.history.value;
return history[history.length - 1];
});
// Clear all history entries
desk.clearHistory();
console.log(desk.getHistory()); // []
<script setup lang="ts">
import { useCheckIn, createHistoryPlugin } from 'vue-airport';
interface Task {
title: string;
completed: boolean;
}
const { createDesk } = useCheckIn<Task>();
const { desk } = createDesk('tasks', {
plugins: [createHistoryPlugin({ maxHistory: 50 })]
});
const history = computed(() => desk.getHistory());
const formatTime = (timestamp: number) => {
return new Date(timestamp).toLocaleTimeString();
};
const getActionIcon = (action: string) => {
switch (action) {
case 'check-in': return 'i-heroicons-plus-circle';
case 'update': return 'i-heroicons-arrow-path';
case 'check-out': return 'i-heroicons-minus-circle';
default: return 'i-heroicons-question-mark-circle';
}
};
const getActionColor = (action: string) => {
switch (action) {
case 'check-in': return 'text-green-500';
case 'update': return 'text-blue-500';
case 'check-out': return 'text-red-500';
default: return 'text-gray-500';
}
};
</script>
<template>
<div class="history-timeline">
<h2>Operation History ({{ history.length }})</h2>
<div class="timeline">
<div
v-for="(entry, index) in history.slice().reverse()"
:key="index"
class="timeline-entry"
>
<UIcon
:name="getActionIcon(entry.action)"
:class="getActionColor(entry.action)"
/>
<span class="time">{{ formatTime(entry.timestamp) }}</span>
<span class="action">{{ entry.action }}</span>
<span class="id">{{ entry.id }}</span>
<span v-if="entry.data" class="data">
{{ entry.data.title }}
</span>
</div>
</div>
<UButton
v-if="history.length > 0"
color="neutral"
variant="outline"
@click="desk.clearHistory()"
>
Clear History
</UButton>
</div>
</template>
Watch for specific operations as they occur:
<script setup lang="ts">
import { useCheckIn, createHistoryPlugin } from 'vue-airport';
const { createDesk } = useCheckIn();
const { desk } = createDesk('monitored-items', {
plugins: [createHistoryPlugin({ maxHistory: 100 })]
});
// Watch for new operations
watch(() => desk.history.value.length, (newLength, oldLength) => {
if (newLength > oldLength) {
const latestEntry = desk.history.value[newLength - 1];
console.log('New operation:', latestEntry.action, 'on', latestEntry.id);
// Show notification, update UI, etc.
if (latestEntry.action === 'check-out') {
showNotification(`Item ${latestEntry.id} was removed`);
}
}
});
// Track operation rate
const recentOps = computed(() => {
const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;
return desk.history.value.filter(e => e.timestamp > fiveMinutesAgo).length;
});
</script>
<template>
<div>
<p>Operations in last 5 minutes: {{ recentOps }}</p>
</div>
</template>
getHistory(): HistoryEntry<T>[]Returns the complete history array.
const history = desk.getHistory();
clearHistory(): voidClears all history entries.
desk.clearHistory();
getLastHistory(count: number): HistoryEntry<T>[]Returns the last N history entries.
const last10 = desk.getLastHistory(10);
getHistoryByAction(action: 'check-in' | 'check-out' | 'update'): HistoryEntry<T>[]Returns history entries filtered by action type.
const checkIns = desk.getHistoryByAction('check-in');
const updates = desk.getHistoryByAction('update');
const checkOuts = desk.getHistoryByAction('check-out');
history: Ref<HistoryEntry<T>[]>A reactive reference to the history array.
watchEffect(() => {
console.log('History changed:', desk.history.value);
});
Track all changes for compliance and debugging:
const { desk } = createDesk('records', {
plugins: [createHistoryPlugin({ maxHistory: 1000 })]
});
// Later, review what happened
const auditLog = desk.getHistory().map(entry => ({
timestamp: new Date(entry.timestamp).toISOString(),
action: entry.action,
itemId: entry.id,
details: entry.data
}));
console.table(auditLog);
Track user behavior patterns:
const checkIns = desk.getHistoryByAction('check-in');
const avgTimePerItem = checkIns.reduce((acc, entry, i, arr) => {
if (i === 0) return acc;
return acc + (entry.timestamp - arr[i - 1].timestamp);
}, 0) / Math.max(checkIns.length - 1, 1);
console.log('Average time between check-ins:', avgTimePerItem, 'ms');
Review operation sequence to diagnose issues:
// What operations were performed on this item?
const itemHistory = desk.getHistory()
.filter(entry => entry.id === 'problematic-item');
console.log('Operations on problematic-item:', itemHistory);
Detect when specific changes occurred:
const updates = desk.getHistoryByAction('update');
const recentUpdates = updates.filter(entry =>
entry.timestamp > Date.now() - 60000 // Last minute
);
console.log('Recent updates:', recentUpdates);
Create snapshots at specific points:
const snapshot = {
timestamp: Date.now(),
items: desk.items,
history: desk.getHistory()
};
// Later, compare or restore
maxHistory values with large data objects can consume significant memory. Adjust maxHistory based on your needs.// For debugging, keep more history
createHistoryPlugin({ maxHistory: 200 })
// For production, keep less
createHistoryPlugin({ maxHistory: 50 })
// For analytics with large objects, consider storing only IDs
const { desk } = createDesk('items', {
plugins: [
createHistoryPlugin({ maxHistory: 100 })
]
});
// Periodically export and clear
setInterval(() => {
exportToServer(desk.getHistory());
desk.clearHistory();
}, 60000); // Every minute
const exportHistory = () => {
const history = desk.getHistory();
const json = JSON.stringify(history, null, 2);
// Download as file
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `history-${Date.now()}.json`;
a.click();
};
const getHistoryInRange = (startTime: number, endTime: number) => {
return desk.getHistory().filter(entry =>
entry.timestamp >= startTime && entry.timestamp <= endTime
);
};
// Get today's history
const today = new Date();
today.setHours(0, 0, 0, 0);
const todayHistory = getHistoryInRange(today.getTime(), Date.now());
const getStatistics = () => {
const history = desk.getHistory();
return {
total: history.length,
checkIns: history.filter(e => e.action === 'check-in').length,
updates: history.filter(e => e.action === 'update').length,
checkOuts: history.filter(e => e.action === 'check-out').length,
uniqueItems: new Set(history.map(e => e.id)).size,
timespan: history.length > 0
? history[history.length - 1].timestamp - history[0].timestamp
: 0
};
};
See the Multi-Plugin Example for a complete working implementation using the History Plugin along with Active Item plugin.