Skip to content

[FEATURE] Export history page #148

@codewizdave

Description

@codewizdave

Create a dedicated page to view and manage all exported files.

Description

Add a new "Exports" page in the sidebar that displays a history of all exported files with management capabilities.

Requirements

New Page

  • Add "Exports" item in sidebar navigation
  • Create exports page at /exports route
  • Display table/list of all exports

Export History Table

  • Date/Time column (sortable, default: newest first)
  • Types column (badges showing what was exported)
  • Format column (CSV/Excel/PDF badge)
  • Records count column
  • File path column (truncated with tooltip)
  • Actions column (Open file, Open folder, Delete)

Data Storage

  • Store export history in database or JSON file
  • Record: id, timestamp, types[], format, recordCount, filePath

Actions

  • Open file in default application
  • Open containing folder in file explorer
  • Delete export record (with confirmation dialog using i18n)

UI Features

  • Search/filter by date range
  • Search/filter by format
  • Search/filter by type
  • Sort by column
  • Pagination or infinite scroll for large lists
  • Empty state with i18n message

i18n Support

  • All UI text uses translation keys
  • Date formatting uses locale
  • Number formatting uses locale

Technical Notes

i18n Keys

{
  "exports": {
    "title": "Historique des exports",
    "columns": {
      "date": "Date",
      "types": "Types",
      "format": "Format",
      "records": "Enregistrements",
      "path": "Chemin",
      "actions": "Actions"
    },
    "actions": {
      "openFile": "Ouvrir le fichier",
      "openFolder": "Ouvrir le dossier",
      "delete": "Supprimer"
    },
    "filter": {
      "search": "Rechercher...",
      "format": "Format",
      "type": "Type",
      "all": "Tous"
    },
    "empty": {
      "title": "Aucun export",
      "description": "Vos exports apparaitront ici"
    },
    "confirmDelete": {
      "title": "Supprimer l'export ?",
      "description": "Cette action est irreversible. Le fichier ne sera pas supprime.",
      "confirm": "Supprimer",
      "cancel": "Annuler"
    },
    "badge": {
      "employees": "employes",
      "attachments": "pieces jointes",
      "media": "medias"
    }
  }
}

Database Schema (if using DB)

// src/core/db/schema/exports.ts
import { timestampsWithSoftDelete } from './utils';

export const exports = pgTable('exports', {
  id: serial('id').primaryKey(),
  types: json('types').$type<'employees' | 'attachments' | 'media'>[],
  format: varchar('format', { length: 10 }),
  recordCount: integer('record_count'),
  filePath: text('file_path'),
  createdAt: timestamp('created_at').defaultNow(),
  ...timestampsWithSoftDelete,
});

Alternative: JSON File Storage

// src/core/lib/export-history.ts
type ExportRecord = {
  id: string;
  timestamp: string;
  types: ('employees' | 'attachments' | 'media')[];
  format: 'csv' | 'xlsx' | 'pdf';
  recordCount: number;
  filePath: string;
};

const getHistoryPath = () => path.join(app.getPath('userData'), 'exports-history.json');

const loadHistory = (): ExportRecord[] => {
  const filePath = getHistoryPath();
  if (!fs.existsSync(filePath)) return [];
  return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
};

const saveRecord = (record: ExportRecord) => {
  const history = loadHistory();
  history.unshift(record);
  const trimmed = history.slice(0, 100);
  fs.writeFileSync(getHistoryPath(), JSON.stringify(trimmed, null, 2));
};

const deleteRecord = (id: string) => {
  const history = loadHistory();
  const filtered = history.filter(r => r.id !== id);
  fs.writeFileSync(getHistoryPath(), JSON.stringify(filtered, null, 2));
};

Priority

  • priority:medium

Effort

  • effort:m

Related

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions