Base

History Plugin

Track a complete history of all desk operations.

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.

Installation

import { useCheckIn } from 'vue-airport';
import { createHistoryPlugin } from '@vue-airport/plugins-base';

const { createDesk } = useCheckIn();
const { desk } = createDesk('items', {
  plugins: [
    createHistoryPlugin({ maxHistory: 100 })
  ]
});

Options

maxHistory: number

Maximum 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).

Basic Usage

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 }
// ]

History Entry Structure

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;
}

Retrieving History

Get All History

const history = desk.getHistory();

history.forEach(entry => {
  console.log(`${entry.action} on ${entry.id} at ${new Date(entry.timestamp)}`);
});

Get Last N Entries

// Get last 10 operations
const recent = desk.getLastHistory(10);

// Get last operation
const lastOp = desk.getLastHistory(1)[0];
console.log('Last operation:', lastOp.action);

Filter by Action Type

// 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');

Access Reactive History

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];
});

Clearing History

// Clear all history entries
desk.clearHistory();

console.log(desk.getHistory()); // []

Component Integration

History Timeline

<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>

Real-Time Monitoring

Real-Time Monitoring

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>

Methods

getHistory(): HistoryEntry<T>[]

Returns the complete history array.

const history = desk.getHistory();

clearHistory(): void

Clears 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');

Properties

history: Ref<HistoryEntry<T>[]>

A reactive reference to the history array.

watchEffect(() => {
  console.log('History changed:', desk.history.value);
});

Use Cases

Audit Trail

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);

Analytics

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');

Debugging

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);

Change Detection

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);

State Snapshots

Create snapshots at specific points:

const snapshot = {
  timestamp: Date.now(),
  items: desk.items,
  history: desk.getHistory()
};

// Later, compare or restore

Performance Considerations

Memory usage: The history is stored in memory. Large 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

Advanced Usage

Export History

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();
};

Time-based Filtering

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());

Statistics

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
  };
};

Examples

See the Multi-Plugin Example for a complete working implementation using the History Plugin along with Active Item plugin.