# Dashboard

`Dashboard` 组件为 blocklet 应用程序提供了一个预构建的响应式布局，通常用于管理界面或以用户为中心的视图。它通过解析 blocklet 的元数据，自动构建一个包含侧边栏、头部和主内容区域的标准仪表盘。该组件显著减少了构建常见应用程序结构的样板代码。

该布局由三个主要部分组成：一个用于导航的持久侧边栏，一个用于全局操作和用户信息的头部，以及一个渲染特定页面内容的主内容区域。

<!-- DIAGRAM_IMAGE_START:architecture:16:9:1765962229 -->
![Dashboard](assets/diagram/dashboard-diagram-0.zh.jpg)
<!-- DIAGRAM_IMAGE_END -->

## 基本用法

要使用 `Dashboard` 组件，只需用它包裹页面内容即可。该组件将自动在您的内容周围渲染头部和侧边栏。

```javascript MyDashboard.jsx icon=logos:react
import Dashboard from '@arcblock/blocklet-ui-react/lib/Dashboard';

export default function MyDashboardPage() {
  return (
    <Dashboard>
      <h1>欢迎来到 Dashboard</h1>
      <p>这是您的主内容区域。</p>
    </Dashboard>
  );
}
```

传递给 `Dashboard` 组件的子元素将显示在主内容区域。

## 属性

`Dashboard` 组件接受以下属性以自定义其行为和外观。

<x-field-group>
  <x-field data-name="children" data-type="React.ReactNode" data-required="true">
    <x-field-desc markdown>要在仪表盘布局的主内容区域内渲染的内容。</x-field-desc>
  </x-field>
  <x-field data-name="meta" data-type="object" data-required="false">
    <x-field-desc markdown>一个 blocklet 元数据对象。如果提供，它将与默认的 `window.blocklet` 元数据合并并覆盖后者。这对于测试或动态更改 blocklet 信息非常有用。</x-field-desc>
  </x-field>
  <x-field data-name="fallbackUrl" data-type="string" data-required="false" data-default="publicPath">
    <x-field-desc markdown>如果当前已认证用户根据其角色无权访问任何导航链接，则重定向到此 URL。设置为 `null` 可禁用此自动重定向。</x-field-desc>
  </x-field>
  <x-field data-name="invalidPathFallback" data-type="function" data-required="false">
    <x-field-desc markdown>当当前 URL 路径与任何可用的导航链接都不匹配时执行的回调函数。默认行为是重定向到第一个可用的链接。</x-field-desc>
  </x-field>
  <x-field data-name="headerAddons" data-type="React.ReactNode | function" data-required="false">
    <x-field-desc markdown>允许自定义头部右侧的附加组件。如果提供一个节点，它将替换所有默认的附加组件。如果提供一个函数，它会接收默认附加组件数组作为参数，允许您添加、删除或重新排序它们。</x-field-desc>
  </x-field>
  <x-field data-name="sessionManagerProps" data-type="object" data-required="false">
    <x-field-desc markdown>要直接传递给头部底层 `SessionUser` 组件的属性。这允许自定义用户会话菜单，例如 `showRole` 或定义自定义的 `onLogout` 处理程序。</x-field-desc>
  </x-field>
  <x-field data-name="links" data-type="array | function" data-required="false">
    <x-field-desc markdown>允许以编程方式修改侧边栏导航链接。如果提供一个数组，其项目将附加到从元数据生成的链接后面。如果提供一个函数，它将接收元数据生成的链接作为参数，并应返回一个新的链接数组。</x-field-desc>
  </x-field>
  <x-field data-name="showDomainWarningDialog" data-type="boolean" data-required="false" data-default="true">
    <x-field-desc markdown>如果为 `true`，当应用程序从不受信任的域访问时，将显示一个警告对话框。</x-field-desc>
  </x-field>
</x-field-group>

## 工作原理

`Dashboard` 组件被设计为“配置驱动”，其结构和内容主要来源于 blocklet 的元数据文件（`blocklet.yml`）。

### 从元数据生成导航

侧边栏导航是根据 `blocklet.yml` 中的 `navigation` 数组自动生成的。该组件专门查找其 `section` 属性中包含 `dashboard` 的导航项。

以下是如何定义仪表盘导航的示例：

```yaml blocklet.yml icon=mdi:file-document
navigation:
  - title: 'Home'
    link: '/'
    section: 'dashboard'
    icon: 'mdi:home'
    role: ['owner', 'admin', 'guest']
  - title: 'Analytics'
    link: '/analytics'
    section: 'dashboard'
    icon: 'mdi:chart-bar'
    role: ['owner', 'admin']
  - title: 'Settings'
    link: '/settings'
    section: 'dashboard'
    icon: 'mdi:cog'
    role: ['owner']
    items:
      - title: 'Profile'
        link: '/settings/profile'
      - title: 'Billing'
        link: '/settings/billing'
```

### 基于角色的访问控制

`Dashboard` 组件对导航链接实施基于角色的访问控制（RBAC）。每个导航项可以有一个 `role` 属性，这是一个允许查看该链接的角色数组。

- 如果导航项没有 `role` 属性，则对所有人可见。
- 如果当前用户未认证，他们只能看到包含 `guest` 角色的项目。
- 如果当前用户已认证，组件会将其 `user.role` 与每个导航项的 `role` 数组进行比较。只有在匹配的情况下，该项目才会显示。
- 只有当父导航项至少有一个子项可见时，父导航项本身才可见。

使用上面的 `blocklet.yml` 示例：
- 具有 `guest` 角色的用户将只看到“Home”链接。
- 具有 `admin` 角色的用户将看到“Home”和“Analytics”。
- 具有 `owner` 角色的用户将看到所有链接，包括“Settings”下的嵌套链接“Profile”和“Billing”。

### 图标

导航项的 `icon` 属性应该是一个字符串，对应于 [Iconify](https://icon-sets.iconify.design/) 库中的图标名称（例如，`mdi:home`）。您也可以提供一个指向图像文件的完整 URL。

## 自定义

虽然 `Dashboard` 被设计为可以与元数据开箱即用，但它也提供了几个属性用于更高级的自定义。

### 自定义头部附加组件

您可以使用 `headerAddons` 属性修改默认的头部附加组件（例如，主题切换器、区域设置选择器、会话管理器）。通过传递一个函数，您可以添加新元素或重新排列现有元素。

```javascript CustomHeader.jsx icon=logos:react
import Dashboard from '@arcblock/blocklet-ui-react/lib/Dashboard';
import Button from '@mui/material/Button';

function MyCustomButton() {
  return <Button color="inherit" onClick={() => alert('Help!')}>Help</Button>;
}

export default function CustomDashboard() {
  return (
    <Dashboard
      headerAddons={(existingAddons) => {
        const customAddon = <MyCustomButton key="custom-help" />;
        // 将自定义按钮添加到其他附加组件之前
        return [customAddon, ...existingAddons];
      }}
    >
      <p>带有自定义头部按钮的 Dashboard。</p>
    </Dashboard>
  );
}
```

### 以编程方式添加链接

`links` 属性允许您通过代码动态添加或修改侧边栏导航链接。这对于依赖于应用程序状态的链接非常有用。

```javascript DynamicLinks.jsx icon=logos:react
import Dashboard from '@arcblock/blocklet-ui-react/lib/Dashboard';
import Icon from '@arcblock/ux/lib/Icon';

const useFeatureFlag = () => {
  // 在实际应用中，这里会检查功能开关服务
  return true;
};

export default function DynamicDashboard() {
  const isBetaFeatureEnabled = useFeatureFlag();

  return (
    <Dashboard
      links={(existingLinks) => {
        if (isBetaFeatureEnabled) {
          const betaLink = {
            id: 'beta-feature',
            title: 'Beta Feature',
            url: '/beta',
            icon: <Icon name="mdi:test-tube" />,
            external: true, // 客户端路由所需
          };
          return [...existingLinks, betaLink];
        }
        return existingLinks;
      }}
    >
      <p>此仪表盘可能包含动态链接。</p>
    </Dashboard>
  );
}

```

## 总结

`Dashboard` 组件是快速搭建应用程序布局的强大工具。通过利用 blocklet 元数据，它提供了一个结构化、具备角色感知能力的开箱即用的导航系统。有关更基础的布局组件，请参阅 [Header](./components-layout-header.md) 和 [Footer](./components-layout-footer.md) 的文档。