# @scalio-cloud/ui 中文文档

规范地址：https://npmcn.com/package/%40scalio-cloud/ui/

版本：0\.29\.0
npm 元数据更新时间：2026-11-02T09:49:08.885Z
中文译文更新时间：2026-11-02T10:16:47.450Z
软件包许可：SEE LICENSE IN README\.md

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40scalio-cloud/ui
原文对照：https://npmcn.com/package/%40scalio-cloud/ui/?lang=original
项目主页：https://github.com/Scalio-Cloud/scalio-ui#readme
源码仓库：https://github.com/Scalio-Cloud/scalio-ui

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：696 kB，47 个文件
- 模块格式：CommonJS
- TypeScript 类型：未声明
- Node.js 要求：\>=18
- 运行依赖：0 个
- peer 依赖：react \>=18，react-dom \>=18，tailwindcss \>=3\.3 \<4
- 首次发布：2026-10-25T14:38:04.786Z
- 最新版本发布：2026-11-02T09:49:08.637Z
- 已发布版本数：40（近 12 个月 40 个）

## 中文简介

Scalio控制室设计令牌，顺风预设，自托管字体，共享的应用程序标题，登录布局，侧边栏和页面块

## 安装

```sh
npm install @scalio-cloud/ui
```

也可以使用：`pnpm add @scalio-cloud/ui`、`yarn add @scalio-cloud/ui`、`bun add @scalio-cloud/ui`

## README

# @scalio-cloud / ui

Scalio应用程序（Nexus, Rosetta, Foundry, Citadel, Compass，后来的Pulse）的共享外观和感觉： “控制室”的设计标志，一个顺风预设和字体，从应用程序本身提供。 规范: `design/UISPEC.md` 在 `Scalio-Cloud/scalio-docs` (单一副本)。

| 文件 | 它是什么？ |
| --- | --- |
| `tokens.css` | shadcn/ui CSS变量，亮起 `:root`，暗的 `.dark` (克莱因蓝 `#002FA7`，半径4px) |
| `fonts.css` | `@font-face` 用于Chivo， IBM Plex Sans, JetBrains Mono （woff2，拉丁语，SIL OFL 1.1）。没有谷歌字体请求 |
| `base.css` | 正文/标题/代码字体系列 |
| `shell.css` | 应用标题、用户菜单、页面标题和版本(`scalio-*` 类) |
| `nav.css` | 侧边栏，电话抽屉，切换器，上下文选择，支持抽屉，页面块 |
| `index.css` | 所有这些都在一个导入中 |
| `react/` | React的共享应用头（见下文），除了React之外没有依赖项 |
| `tailwind-preset.js` | 颜色，字体，半径，手风琴动画， `brand` 的颜色, `h-switcher`， `h-header`， `w-sidebar` |
| `tokens.js` | 没有CSS的代码的原始值（图表、电子邮件、pdf） |

## 在应用程序中使用它（CRA/craco或Vite）

```js
// tailwind.config.js
module.exports = {
  presets: [require("@scalio-cloud/ui/tailwind-preset")],
  content: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"],
  plugins: [require("tailwindcss-animate")],
};
```

```css
/* src/index.css, first line */
@import "@scalio-cloud/ui/index.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
```

然后删除应用程序自己的 `:root { --... }` / `.dark { --... }` 块和谷歌字体 `@import` / `<link>`. 类等 `bg-primary`， `rounded-sm`， `font-display` 保持工作不变。

## 应用头（React）

每个应用都在右侧显示相同的标题，总是按照这个顺序：（应用操作），状态，语言，主题， 支持,《阿凡达》。 部件只有在应用程序通过其处理程序时才会出现（Compass没有暗模式，所以没有） `onThemeChange`）。

```jsx
import { AppHeader, PageHeader, VersionTag, manualUrl } from "@scalio-cloud/ui/react";

<AppHeader
  brand={{ mark: "N", name: "Scalio Nexus", sub: "Dev" }}  // or your own element
  onMenu={() => setMobileNavOpen(true)}                     // hamburger below 768px
  left={<TenantSelect />}                                   // after the brand
  actions={<LocalePopover />}                               // right side, before the fixed group
  status={<ApiStatus />}                                    // hidden below 768px
  lang={lang} onLangChange={setLang}                        // one click, shows the other language
  theme={theme} themeModes={["light", "dark", "system"]} onThemeChange={setTheme}
  docsUrl={manualUrl("nexus", { stage, lang })}           // book icon, opens the manual in a new tab
  onSupport={() => setSupportOpen(true)}
  user={{ name, email, role }} onLogout={logout}
  menuItems={[{ label: "Profil", icon: User, onSelect: () => nav("/profile"), testId: "profile-link" }]}
  testIds={{ logout: "logout-button" }}                     // keep an app's existing test ids
/>
<PageHeader eyebrow="Verwaltung" title="Benutzer" subtitle="..." actions={<Button>Neu</Button>} />
<VersionTag version="1.2.4" commit="3f2a1bc" />              // bottom of the sidebar
```

文本是内置的 `lang` `de` 和 `en` 并且可以被覆盖 `labels`。默认测试id （`language-toggle-btn`， `theme-toggle-btn`， `support-ticket-trigger`， `user-avatar-btn`， `logout-btn`)都在 `TEST_IDS`。组件是普通的CommonJS `React.createElement`，所以CRA、Vite和Jest不需要额外的配置。 图标是内联的(Lucide， ISC，参见 `licenses/`）。

## 侧边栏，切换器和页面块（React）

每个应用程序都有相同的帧（UISPEC“导航”）：切换器，标题与上下文选择在左边，然后 侧边栏搜索，最多一个主要操作，“Übersicht”，最多三个部分和“Verwaltung”最后 （Protokoll, Konten und rolen, einstein）配置文件和个人页面只存在于用户菜单中。应用程序 将其导航描述为数据；侧边栏、电话抽屉和（后来的）搜索读取相同的列表。

```jsx
import { NavLink } from "react-router-dom";
import { AppShell, Sidebar, ProductSwitcher, ContextSelect, SupportDrawer, useScalioApps,
  KpiTile, EmptyState, Loading, Notice, StatusBadge, LABELS } from "@scalio-cloud/ui/react";

const L = LABELS[lang];
const NAV = { sections: [
  { id: "main", items: [{ to: "/", label: L.overview, icon: LayoutGrid, end: true }] },
  { id: "compliance", label: t("Compliance"), items: [
    { to: "/drifts", label: t("Drifts"), icon: GitCompareArrows, badge: open || null, badgeTone: "error" },
  ] },
  { id: "admin", label: L.administration, items: [
    { to: "/audit", label: L.auditLog, icon: ScrollText },
    { to: "/accounts", label: L.accounts, icon: Users, hidden: !isAdmin },   // hidden items and empty sections disappear
    { to: "/settings", label: L.settings, icon: SlidersHorizontal },
  ] },
] };

const apps = useScalioApps(() => api.get("/apps").then((r) => r.data));   // once per page load
<AppShell
  switcher={apps.features.switcher && <ProductSwitcher current="citadel" links={apps.links} stage={apps.stage} sso={sso} lang={lang} />}
  header={<AppHeader ... onMenu={() => setDrawer(true)}
    left={<ContextSelect label={L.tenant} value={tenantId} options={tenants} onChange={select} hint={domain} testId="tenant-switcher" />} />}
  sidebar={<Sidebar nav={NAV} link={NavLink} lang={lang} version={VERSION} commit={COMMIT}
    search={{ onOpen: openPalette, shortcut: "⌘K" }} primaryAction={{ label: t("Scan starten"), icon: Play, onSelect: scan }} />}
  drawerOpen={drawer} onDrawerClose={() => setDrawer(false)}   // phones: same sidebar in a drawer (test ids with "m-")
  drawerTop={<ContextSelect ... testId="m-tenant-switcher" />}  // below 640px the header hides the select, the drawer shows it
>
  <Routes>...</Routes>
</AppShell>
<SupportDrawer open={supportOpen} onClose={...} lang={lang} client={supportApi(api)} page={location.pathname}
  context={[["URL", location.pathname], [L.tenant, current?.name]]} />
```

与 `client` 抽屉里有“Neue Anfrage”标签（类别、主题、描述、技术细节）和 “我的票”（列表、回答、回复、评分）；机票到Compass （scalio-docs ADR）的中央服务台 0022)，后端路由来自scalio-connect `scalio_connect.support.web`. `supportApi(api)` 取应用程序的 axios实例。设置卡 `<SupportConnection client={supportApi(api)} lang={lang} />` 连接 安装使用一次性代码（admins）。没有 `client` 抽屉里保存着旧的单张表格 `onSubmit`. `supportApi(api, { ideas: true })` 添加标签“Ideen”（Scalio Ideen, ADR 0050；后端路由器） `scalio_connect.support.ideas_web.ideas_router`（scalio-connect 0.8.0）：应用程序的想法与投票和评论和 “Idee vorschlagen”也有类似的想法；然后是“unsch”类别。

设置卡 `<BeaconConnection client={peersApi(api)} lang={lang} />` 将应用程序与Scalio Beacon配对 （地址和一次性代码来自Beacon， Einstellungen -> Verbundene Apps）；然后将调查结果交给Beacon公司。后端: scalio-connect 0.8.0 `peers.web.admin_router`.

`link` 是路由器的 `NavLink` (就 `to`， `end`,一个 `className` 功能和 `onClick`）; 没有它 工具条显示普通链接并将项目标记为 `activePath`。项目test id默认为 `nav-<path>` （`nav-overview` 用于 `/`)，或设置 `testId`。页面: `KpiTile` (语气 `error` =红色数字)， `EmptyState` （孩子=下一步）， `Loading`， `Notice` （`error` 红色=费勒； `warn`/`important` 橙色= wichtig, `ok`/`success` 绿色=融化； `info`/`action` 蓝色=行动； `banner` =全宽)， `StatusBadge` (音调 `neutral`， `running`， `ok`， `warn`， `error`), `PageHeader` 与 `back` 查看详细页面。

属于一个菜单项的页面保留自己的地址：该菜单项将它们列在其中 `match` （`{ to: "/groups", label: "Gruppen", match: ["/teams", "/distribution-lists"] }`,通过 `activePath` 与 `link`)，每页显示 `<SubNav items={[{ to: "/groups", label: "Sicherheit", end: true }, ...]} link={NavLink} />` 在上面。一个有两个工作区域（Nexus Identity和HR）的应用程序 `<WorkspaceSwitcher options value onSelect />` 进入侧边栏 `top`.

**侧边栏中的页面操作** （从0.18.0开始，ispec第2节）： `<Sidebar pageActions ... />` 保持Übersicht ( 第一部分的第一项（没有标题），并在它的正下方添加一个插槽。页面将其操作封装在 `<PageActions>`;从768px他们移动到槽，在手机上，他们留在页眉。槽位不接受 没有动作的页面空间；通过操作，它将菜单向下推。

```jsx
<PageHeader title="Kontakte" actions={<PageActions><Button onClick={add}><Plus /> Kontakt</Button></PageActions>} />
<PageHeader title={doc.number} actions={<PageActions><Button variant="outline" asChild><Link to="/invoices"><ArrowLeft /> Zurück</Link></Button></PageActions>} />
```

只有开始或引导的操作才会出现在那里（新建，导入，扫描，扫描<e:1>），每页最多两个。 没有“新”/“新”的标签：+图标表示它（“+ Kontakt”，而不是“+ Neuer Kontakt”）。 过滤器，搜索，标签和specichern留在页面上。有自己侧边栏位置的应用程序 `<ActionSlot />` 他们自己。

## 设置页面（React）

设置的每个区域都有自己的地址(`/settings/<area>`）; 应用程序的路由器会选择该区域 布局绘制子导航，面包屑（“Einstellungen›Verbindungen”）和标题。组 `general`， `connections`， `notifications`， `security` 和 `system` 得到他们的名字 `LABELS` 一直坐在这里 订单，应用程序自己的组(与 `label`)跟在“Allgemein”后面。隐藏区域和空组消失在下面 三个领域(`minItems`)，没有子导航。搜索将查看标签、提示、组和 `keywords`； `search={false}` 忽略它， `search={<OwnSearch />}` 将应用程序自己的搜索放在那里。

```jsx
import { SettingsLayout, SettingsSection } from "@scalio-cloud/ui/react";

const GROUPS = [
  { id: "general", items: [{ id: "general", to: "/settings/general", label: "Instanz", hint: "Name, Sprache, Zeitzone" }] },
  { id: "flows", label: "Abläufe", items: [{ id: "onboarding", to: "/settings/onboarding", label: "Onboarding" }] },
  { id: "connections", items: [{ id: "sync", to: "/settings/sync", label: "Synchronisierung", keywords: ["Intervall"] }] },
  { id: "system", items: [{ id: "updates", to: "/settings/updates", label: "Updates", hidden: saas }] },
];

<SettingsLayout groups={GROUPS} active={area} link={NavLink} onSelect={(i) => navigate(i.to)} lang={lang}>
  <SettingsSection id="cloud-sync" title="Cloud-Synchronisierung" description="Intervall und Umfang."
    footer={<Button onClick={save}>Speichern</Button>}>
    ...form fields (shadcn)...
  </SettingsSection>
</SettingsLayout>
```

## 登录页面和配置文件（React）

所有登录页面都使用相同的框架和顺序：Microsoft先，然后是“order mit E-Mail”，密码字段为 在它下面，是提交按钮。忘记密码，重置，验证电子邮件和两个步骤是 他们自己的页面在同一个框架里。只显示应用程序可以做什么（仅在Compass中注册，演示帐户仅限） 在演示模式下)。

```jsx
import { AuthLayout, AuthHeader, MicrosoftButton, AuthDivider, AuthMessage, ProfileSection } from "@scalio-cloud/ui/react";

<AuthLayout
  brand={{ mark: "N", name: "Scalio Nexus", claim: "Alle Konten aus einer Konsole verwalten.",
           features: ["Onboarding", "Ändern", "Offboarding"] }}
  lang={lang} onLangChange={setLang}                 // top right
  theme={theme} onThemeChange={setTheme}             // optional
  footer={<VersionTag version={v} />}                // optional
>
  <AuthHeader eyebrow="Zugang" title="Anmelden" subtitle="..." />
  <MicrosoftButton href="/api/auth/sso/login" lang={lang} disabled={!ssoReady} hint="..." />
  <AuthDivider lang={lang} />
  <form>...</form>
  <AuthMessage kind="error">{error}</AuthMessage>
</AuthLayout>

// Profile page: the same sections in every app, leave out what an app does not need.
<ProfileSection id="account" lang={lang}>...</ProfileSection>      // Konto
<ProfileSection id="appearance" lang={lang}>...</ProfileSection>   // Darstellung
<ProfileSection id="language" lang={lang}>...</ProfileSection>     // Sprache und Region
<ProfileSection id="security" lang={lang}>...</ProfileSection>     // Sicherheit
<ProfileSection id="connections" lang={lang}>...</ProfileSection>  // Verknüpfungen
```

章节内容（每个应用都一样，参考Nexus）： `ProfileIdentity` 在Konto, `ThemeChoice` 在 Darstellung, `LanguageChoice` + `TimezoneChoice` 在Sprache und Region， `PasswordChange` + `SecurityFactors` 在 Sicherheit。应用程序存储时区(`POST /auth/preferences {timezone}`),电话 `setUserTimezone()` 与 的值 `/auth/me` 并将日期格式化为 `timeZone: currentTz()`. `applyTheme(mode)` 设置dark类 适用于光、暗、系统。

其他表单字段和按钮（例如name字段）保持应用程序自己的（shadcn），因此它们与应用程序的其余部分匹配。

## 用户管理（React）

Konten und rolen→Benutzer，每个应用程序都一样（ADR 0059）。后端遵循scala -docs `interfaces/app-users.md`； `usersApi(api, {base: "/admins"})` 连结。

```jsx
import { UserAdmin, usersApi, MicrosoftConnection } from "@scalio-cloud/ui/react";

const users = usersApi(api);   // once, outside the component
<UserAdmin client={users} me={user.id} lang={lang} roles={[{ value: "admin", label: t("Administrator") }, ...]}
  defaultRole="operator" signInModes={["microsoft", "password"]} microsoftEnabled={ssoOn} canLock
  accessColumn={{ label: t("Customers"), render: (u) => ... }} accessField={(value, onChange, role, u) => ...}
  notify={(text, tone) => toast[tone](text)} confirm={confirm} formatError={fmt} />

// Profile -> Verknüpfungen
<MicrosoftConnection linked={user.microsoft} canUnlink={user.has_password} onLink={...} onUnlink={...} lang={lang} />
```

### Microsoft Entra (`RoleAdmin`， `RoleSourceSettings`）

```jsx
import { RoleAdmin, rolesApi, RoleSourceSettings } from "@scalio-cloud/ui/react";
const roles = rolesApi(api);                               // Nexus: rolesApi(api, { permissions: "/permissions" })
<RoleAdmin client={roles} lang={lang} notify={toast} confirm={confirm} onChange={reloadUsers} />
<RoleSourceSettings value={source} tenants onSave={({ source, tenants }) => api.put("/users/role-source", { source, tenant_ids: tenants })} lang={lang} />
```

后端是规模平台 `roles_router` (0.3.0)。内置角色是只读的；自己的角色永远得不到 应用程序为管理员保留的权限。

## 设置向导（React）

第一次登录后，在每个应用程序中都一样（ADR 0060， uspec第3节）。应用程序写道 只有它的脚步；后端遵循scala -docs `interfaces/setup-wizard.md` （`GET/PUT /api/setup/wizard`）。

```jsx
import { SetupWizard, SetupWizardButton, useSetupWizard, setupWizardApi } from "@scalio-cloud/ui/react";

const wizardClient = setupWizardApi(api);   // once, outside the component ({ base: "/wizard" } for another route)

function AppWizard() {
  const w = useSetupWizard({ client: wizardClient, enabled: isAdmin });   // opens by itself while needed
  const steps = [
    { id: "tenant", label: t("Tenant"), title: t("Connect Microsoft"), description: "...", content: <TenantsSection />,
      canNext: connected, onNext: async () => { /* save; a rejected promise keeps the step open */ } },
    { id: "mail", label: t("Email"), title: t("Email (SMTP)"), content: <SmtpForm />, optional: true },
  ];
  return <SetupWizard {...w.props} lang={lang} title={t("Set up Foundry")} subtitle={t("...")} steps={steps}
    success={{ title: t("Setup complete"), text: t("...") }} />;
}

// Einstellungen: open it again (admins only)
<SetupWizardButton lang={lang} />
```

测试id: `setup-wizard`， `wizard-stepper(-item)`， `wizard-step-{id}`， `wizard-next`， `wizard-back`， `wizard-skip`， `wizard-close`， `wizard-error`， `wizard-success`， `wizard-done`， `settings-open-wizard`.

## 双因素卡和许可面板（React）

每个应用程序中都有相同的后端路由，因此应用程序只传递它们的axios实例和一些helper。

```jsx
import { SecurityFactors, securityApi, LicensePanel, licenseApi } from "@scalio-cloud/ui/react";
import { QRCodeSVG } from "qrcode.react";
import { startRegistration, browserSupportsWebAuthn } from "@simplewebauthn/browser";

const security = securityApi(api, { startRegistration, browserSupportsWebAuthn });   // once, outside the component
const license = licenseApi(api);

// Profile -> Sicherheit: authenticator app, backup codes, passkeys. Hidden for accounts without a password.
<SecurityFactors client={security} lang={lang} product="Scalio Citadel" email={user.email}
  qr={(uri) => <QRCodeSVG value={uri} size={160} />} notify={(text, tone) => toast[tone](text)}
  confirm={confirm} onMfaChange={(on) => setUser({ ...user, mfa_enabled: on })} />

// Einstellungen -> System -> Lizenz (scalio-license backend: /license, /license/addons)
<LicensePanel client={license} lang={lang} product="Citadel" kindLabel={licenseKindLabel}
  featureLabel={licenseFeatureLabel} noFeatures={t("Drift detection only")} notify={...} confirm={confirm} />
// noFeatures only when the app has a better text than «Nur die Grundfunktionen»
```

`securityApi` 读取snake\_case和camelCase的答案。 `notify(text, tone)` 得到 `"success"` 或者 `"error"`;没有它 这些块本身显示信息。 `confirm` 应用程序的对话框(`{title, action, danger}` - >承诺), `window.confirm` 否则。 `formatError(err)` 让应用程序短语API错误（例如许可证限制代码）。有其他路由的license后端传递自己的路由 `client` 和一个 `map(license, {L})` 中描述的视图模型 `react/license.js`． Nexus做到了这一点：它 `map` 添加试用徽章，座位提示，无效 附加组件和只读注释（演示模式），并将其试用通知传递为 `statusExtra` 提醒设置为 `children`.

从0.27.0 （ADR 0069）开始，面板在设置表单中显示三个区域（左边是标题和提示，右边是卡片） Nutzung»，«Add-ons»，«lizenzschlssel»。 `children` 与 `extraTitle` (和 `extraHint`)成为第四个领域。面板通过其 `lang` 每一个 `client` 调用; `licenseApi` 将其发送为 `?lang=`因此，scalio-license 0.4.0以页面语言呈现警告和错误。

## Gruppe系统：zur<s:1> cksetzen和helpers （React）

每个应用程序都以相同的顺序显示Einstellungen→System: Lizenz， Updates, Sicherung, zur<s:1> cksetzen （）`settingsGroups` 对组进行排序 `system` 这种方式)。重置块与scalio-platform对话 `factory_reset` （`GET`/`POST /api/admin/factory-reset`):

```jsx
import { FactoryReset, factoryResetApi, SettingsField, SettingsRow } from "@scalio-cloud/ui/react";

const reset = factoryResetApi(api);   // once, outside the component
<FactoryReset client={reset} lang={lang} tokenKey="citadel_token" backupTo="/settings/backup" link={Link} />
```

`SettingsField` （标签，字段，帮助）和 `SettingsRow` (左边是标题和帮助，右边是开关或按钮； `tone="danger"`） 将字段保持在 `SettingsSection` 每个应用程序都是一样的。

## Benachrichtigungen: E-Mail-Versand and E-Mail-Vorlagen （React）

自0.29.0 （ADR 0069 W5）以来，每个应用程序都以相同的方式发送邮件。服务器端是scalio-platform 0.8.0 `mail` （`Mailer.router`，安装于 `/api/mail`）. 两个块都进入设置组«Benachrichtigungen»。

```jsx
import { MailTransport, MailTemplates, mailApi } from "@scalio-cloud/ui/react";
import { RichTextEditor } from "@/components/RichTextEditor";   // optional, the app's own editor (Compass: react-quill-new)

const mail = mailApi(api);   // once, outside the component; mailApi(api, "/admin/mail") for another prefix
<MailTransport client={mail} lang={lang} notify={toast} graphHint={t("...Mail.Send and Mail.ReadWrite...")}>
  <InboxSettings />           {/* optional blocks after «Testmail» */}
</MailTransport>
<MailTemplates client={mail} lang={lang} editor={RichTextEditor} />
```

`MailTransport` 显示三个块：«E-Mail-Versand»(关闭，SMTP或Microsoft 365，发件人，语言；秘密回来 作为掩码，掩码原封不动地发送回来)，«Testmail»（空收件人：to me）和«Letzte Mails»(`outbox={false}` 隐藏)。在测试实例中，后端响应 `test_mailbox: true` 服务器字段被锁定。 `MailTemplates` 选择邮件和语言，提供占位符作为按钮，显示真实呈现的预览 在沙盒框架中，并保存，测试（«Test an mich»）或重置为内置文本。一个可切换的邮件得到 复选框“已发送的邮件”。这个 `editor` 得到 `{value, onChange, testId}`;如果没有它，则使用文本字段，因此 包不保留任何依赖项。使用编辑器，普通内置文本作为段落(`textToHtml`）。

## 协议：动作和工作（React）

一个菜单项«协议»有两个标签，如Nexus （scalio-docs ADR 0070）。服务器端是规模平台 `audit_router` 和 `jobs_router` (0.7.0)。

```jsx
import { AuditNav, AuditLog, JobsPanel, auditApi, jobsApi } from "@scalio-cloud/ui/react";

const audit = auditApi(api);   // GET /audit, /audit/export.csv
const jobs = jobsApi(api);     // GET /jobs, /jobs/runs, /jobs/queue, POST /jobs/{key}/run, queue actions

<PageHeader title={L.auditLog} nav={<AuditNav link={NavLink} lang={lang} />} />
<AuditLog client={audit} lang={lang} notify={toast} actionLabel={(a, lang) => ACTIONS[lang][a]} tenantLabel="Kunde" />
<JobsPanel client={jobs} lang={lang} notify={toast} canRun={can("jobs.run")} link={Link} confirm={confirm} />
```

-   `AuditLog`：注意«unveränderlich»，芯片计数（从服务器的类别），搜索，过滤器的行动， 状态、租户和时间范围、可排序列、列选择器（人员、租户、IP）、具有相同过滤器的CSV、 “Ältere laden”（光标），用“alt→new”查看，手机上的卡片。配件: `toolbar`， `rowActions(entry)`， `renderDetail(entry)` （Nexus KI, Citadel PDF， Nexus步骤）。
-   `JobsPanel`：选项卡Warteschlange（仅当应用程序有一个），Läufe（按作业和状态过滤）和Hintergrundjobs (时间表，最后一次运行，最后的结果，«Jetzt ausf<s:1> hren»与 `canRun`）; 每15秒重新装填一次(`pollMs`）. 配件: `queueActions(item, reload)`， `renderQueueDetail(item, reload)`.
-   `AuditNav`：标签 `/audit` 和 `/jobs` （`base` 对于另一个前缀， `jobs={false}` 隐藏工作)。

## 命令面板（React）

读取与侧边栏相同的导航数据。将其放入布局中；侧边栏搜索按钮打开它。

```jsx
import { CommandPalette, openCommandPalette, paletteShortcut } from "@scalio-cloud/ui/react";

<Sidebar nav={nav} search={{ onOpen: openCommandPalette, shortcut: paletteShortcut(lang) }} ... />
<CommandPalette nav={nav} activePath={location.pathname} onNavigate={navigate} lang={lang}
  pages={[{ to: "/profile", label: "Profil" }]}
  groups={(query) => [{ id: "ai", label: "KI", order: 10, items: [{ id: "ask", label: `Fragen: ${query}`, onSelect: ask, hidden: !query }] }]} />
```

页面：每个可见的侧边栏项目加上 `pages` （每条路径一次），按标签搜索， `keywords`、截面和路径。 分组排序 `order` (默认60);最近的页面（50）只在查询为空时显示，页面排在最后（100）。 一个项目有 `label`， `icon`， `to` 或者 `onSelect`，可选 `keywords`， `hint`， `tone` （`primary`， `danger`)， `testId` 和 `alwaysShow`． 没有 `open` 面板处理⌘K / Ctrl+K和 `openCommandPalette()` 本身; 通过 `open` + `onOpenChange` 来控制它。 `recentKey` 设置localStorage键(`false`：最近没有)。

## 安装

在npmjs.com上公开，不需要令牌： `yarn add @scalio-cloud/ui` （固定准确的版本）。 包中只包含SIL OFL下的设计值和字体，没有任何机密。

## 许可证

设计令牌和预设：(c) Scalio Cloud LLC，可在Scalio应用程序中免费使用。字体：SIL开放字体许可证1.1， 看到 `fonts/licenses/`． 图标在 `react/icons.js`Lucide， ISC许可，参见 `licenses/lucide-LICENSE.txt`.

## 释放

1.  更改文件和bump `version` 在 `package.json` 无标签；无标签 `v`）。
2.  合并 `main`，然后发布它：在Scalio Dev驾驶舱（在Scalio UI中，“Freigeben”与版本一起）或 在GitHub中（Actions -> publish ->在main上运行工作流，或者自己创建标签/发布）。这个 `publish` Workflow测试并通过可信发布（无令牌；NPM org）将该版本发布到npmjs.com `scalio-cloud`，可信发布者Scalio-Cloud / scalio-ui / publish。Yml)和，当由手或从 使用CHANGELOG行创建标签和GitHub发布。变更日志位于scalio-docs中 `changelog/scalio-ui/` （ADR 0066）：每次更改都会添加一个文件 `changelog.d/<name>.md` 在那里，在释放a之前 文档公关运行 `python3 tools/changelog.py --repo scalio-ui release <version>`.
3.  应用程序更新 `yarn upgrade @scalio-cloud/ui@<version>` 在他们自己的公关中。

`npm test` 检查：亮/暗变量匹配，预设只使用定义的变量，所有字体文件存在， 没有从网络中加载任何内容。

## 常见问题

### @scalio-cloud/ui 是什么？

Scalio控制室设计令牌，顺风预设，自托管字体，共享的应用程序标题，登录布局，侧边栏和页面块

### 如何安装 @scalio-cloud/ui？

在项目目录运行 npm install @scalio-cloud/ui，或使用 pnpm add / yarn add / bun add。

### @scalio-cloud/ui 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/scalio-cloud\_\_ui 是否存在。

### @scalio-cloud/ui 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @scalio-cloud/ui 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @scalio-cloud/ui 可以商用吗？

@scalio-cloud/ui 使用 SEE LICENSE IN README\.md 许可。许可条款写在包内的独立文件中，请阅读该文件确认可否商用。以上为概括，不构成法律意见，请以许可原文为准。

### @scalio-cloud/ui 还在维护吗？

最新版本 0\.29\.0 发布于 2026/11/02（1 天前）；至今共发布 40 个版本，其中过去 12 个月发布了 40 个；首次发布于 2026/10/25。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

