QUESTPIE
Build Your WorkspaceViews

Dashboard

Configure the admin dashboard — stats, charts, progress bars, recent items, and activity timelines.

The dashboard is the admin landing page. Configure it with dashboard.ts — define sections, widgets, and data loaders.

Basic Setup

dashboard.ts
import { dashboard } from "#questpie/factories";

export default dashboard({
	title: { en: "Dashboard" },
	description: { en: "Overview of your app" },
	columns: 4,
});

Actions

Quick-action buttons at the top of the dashboard:

actions: [
  {
    id: "new-appointment",
    href: "/admin/collections/appointments?create=true",
    label: { en: "New Appointment" },
    icon: { type: "icon", props: { name: "ph:calendar-plus" } },
    variant: "primary",
  },
  {
    id: "add-barber",
    href: "/admin/collections/barbers?create=true",
    label: { en: "Add Barber" },
    icon: { type: "icon", props: { name: "ph:user-plus" } },
    variant: "outline",
  },
],

Sections

Group widgets into labeled sections:

sections: [
  {
    id: "today",
    label: { en: "Today" },
    layout: "grid",
    columns: 4,
  },
  {
    id: "business",
    label: { en: "Business" },
    layout: "grid",
    columns: 4,
  },
],

Widget Types

Stats

Count records with optional filters:

{
  sectionId: "today",
  id: "pending-appointments",
  type: "stats",
  collection: "appointments",
  label: { en: "Pending" },
  filter: { status: "pending" },
  span: 1,
}

Value

Custom-loaded value with trend indicator:

{
  sectionId: "business",
  id: "monthly-revenue",
  type: "value",
  span: 2,
  refreshInterval: 1000 * 60 * 5,
  loader: async ({ app }) => {
    const stats = await getRevenueStats.handler({
      input: { startDate, endDate, completedOnly: true },
      app,
    });

    return {
      value: stats.totalRevenue / 100,
      formatted: `${(stats.totalRevenue / 100).toLocaleString()} €`,
      label: { en: "Monthly Revenue" },
      subtitle: { en: `${stats.appointmentCount} completed` },
      trend: { value: "+12%" },
    };
  },
}

Progress

Progress bar toward a goal:

{
  sectionId: "business",
  id: "revenue-goal",
  type: "progress",
  span: 1,
  showPercentage: true,
  label: { en: "Monthly Goal" },
  loader: async ({ app }) => ({
    current: currentRevenue,
    target: 500000,
    label: `${current} / ${target}`,
  }),
}

Chart

Chart from field values:

{
  sectionId: "business",
  id: "appointments-by-status",
  type: "chart",
  collection: "appointments",
  field: "status",
  chartType: "pie",
  label: { en: "Appointments by Status" },
  span: 1,
}

Recent Items

List recent records from a collection:

{
  sectionId: "operations",
  id: "recent-appointments",
  type: "recentItems",
  collection: "appointments",
  label: { en: "Recent Appointments" },
  limit: 6,
  dateField: "scheduledAt",
  span: 2,
}

Timeline

Activity stream with custom loader:

{
  sectionId: "operations",
  id: "activity-stream",
  type: "timeline",
  label: { en: "Activity" },
  maxItems: 8,
  showTimestamps: true,
  timestampFormat: "relative",
  loader: async ({ app }) => {
    const res = await app.collections.appointments.find({
      limit: 8,
      orderBy: { updatedAt: "desc" },
    });

    return res.docs.map((apt) => ({
      id: apt.id,
      title: apt.displayTitle,
      description: `Status: ${apt.status}`,
      timestamp: apt.updatedAt,
      variant: apt.status === "completed" ? "success" : "warning",
      href: `/admin/collections/appointments/${apt.id}`,
    }));
  },
  span: 2,
}

Module Contributions

Modules can contribute dashboard items. The auditModule automatically adds an audit timeline widget to the dashboard.

On this page