Global Menu Component

Build full-page views in the top navigation

Global Menu Component

Global Menu components appear in Fireberry's top navigation bar and render as full-page views. They're ideal for dashboards, admin panels, and standalone tools that need dedicated space.


When to Use

  • Dashboards with metrics and charts
  • Admin or settings panels
  • Reports and analytics
  • Standalone tools not tied to specific records

Manifest Configuration

components:
  - type: global-menu
    title: "Analytics Dashboard"
    id: "analytics-uuid"
    path: static/dashboard/build
    settings:
      displayName: "Analytics"

Settings

SettingTypeRequiredDescription
displayNamestringYesText shown in the navigation bar

displayName

The label that appears in the top navigation. Keep it short — one or two words works best.

Good examples: Analytics, Dashboard, Reports, Admin, Settings


Context Access

Global Menu components have access to user context only — not record context:

import FireberryClientSDK from "@fireberry/sdk/client";

const client = new FireberryClientSDK();
await client.initializeContext();

const { user } = client.context;

console.log(user.id); // "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
console.log(user.fullName); // "John Doe"

// record is NOT available in Global Menu components
// client.context.record will be empty

Example: Dashboard

A simple dashboard with statistics:

import { useEffect, useState } from "react";
import FireberryClientSDK from "@fireberry/sdk/client";
import { DSThemeContextProvider, Typography, Button } from "@fireberry/ds";

function Dashboard() {
  const [client] = useState(() => new FireberryClientSDK());
  const [stats, setStats] = useState({ total: 0, active: 0, completed: 0 });
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function loadStats() {
      await client.initializeContext();

      // Fetch counts
      const [total, active, completed] = await Promise.all([
        client.api.query(1, { fields: "id", query: 'id != ""' }),
        client.api.query(1, { fields: "id", query: 'status = "active"' }),
        client.api.query(1, { fields: "id", query: 'status = "completed"' }),
      ]);

      setStats({
        total: Array.isArray(total.data) ? total.data.length : 1,
        active: Array.isArray(active.data) ? active.data.length : 1,
        completed: Array.isArray(completed.data) ? completed.data.length : 1,
      });

      setLoading(false);
    }

    loadStats();
  }, [client]);

  if (loading) return <div>Loading...</div>;

  return (
    <DSThemeContextProvider isRtl={false}>
      <div style={{ padding: 32, maxWidth: 1200, margin: "0 auto" }}>
        <Typography type="h1">Dashboard</Typography>

        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
            gap: 24,
            marginTop: 32,
          }}
        >
          <StatCard label="Total" value={stats.total} />
          <StatCard label="Active" value={stats.active} />
          <StatCard label="Completed" value={stats.completed} />
        </div>
      </div>
    </DSThemeContextProvider>
  );
}

function StatCard({ label, value }) {
  return (
    <div
      style={{
        padding: 24,
        border: "1px solid #E2E3E9",
        borderRadius: 8,
        backgroundColor: "#fff",
      }}
    >
      <Typography type="caption" color="neutral">
        {label}
      </Typography>
      <Typography type="h1">{value}</Typography>
    </div>
  );
}

Example: Settings Panel

An admin settings page:

import { useState, useEffect } from "react";
import FireberryClientSDK from "@fireberry/sdk/client";
import {
  DSThemeContextProvider,
  Typography,
  Toggle,
  Button,
} from "@fireberry/ds";

function SettingsPanel() {
  const [client] = useState(() => new FireberryClientSDK());
  const [settings, setSettings] = useState({
    notifications: true,
    autoSave: false,
  });

  useEffect(() => {
    client.initializeContext();
  }, [client]);

  const toggle = (key) => {
    setSettings((prev) => ({ ...prev, [key]: !prev[key] }));
  };

  return (
    <DSThemeContextProvider isRtl={false}>
      <div style={{ padding: 32, maxWidth: 600, margin: "0 auto" }}>
        <Typography type="h1">Settings</Typography>

        <div style={{ marginTop: 32 }}>
          <div style={{ marginBottom: 24 }}>
            <Typography type="text">Enable Notifications</Typography>
            <Toggle
              isSelected={settings.notifications}
              onChange={() => toggle("notifications")}
            />
          </div>

          <div style={{ marginBottom: 24 }}>
            <Typography type="text">Auto-Save</Typography>
            <Toggle
              isSelected={settings.autoSave}
              onChange={() => toggle("autoSave")}
            />
          </div>

          <Button label="Save" color="success" variant="primary" />
        </div>
      </div>
    </DSThemeContextProvider>
  );
}

Use Cases

Use CaseDescription
DashboardMetrics, KPIs, overview
ReportsData visualization
Admin PanelSystem configuration
Import/ExportBulk data operations
Help CenterDocumentation

Validation Errors

ErrorSolution
displayName is requiredAdd displayName to settings

Next Steps