@cloud-ru/ds-uikit-product-quota

中文文档
2.1.0发布于 2026/11/11Apache-2.0TypeScriptESM + CJS近 30 天下载 4640

Виджеты квот проекта — выпадающий QuotaWidget, аккордеон QuotaWidgetMini и карточка квоты QuotaWidgetCard с прогрессом и состояниями loading/error.

原始使用文档
文档目录20 节
  1. Установка
  2. Figma
  3. QuotaWidget
  4. Когда использовать
  5. Анатомия
  6. Примеры использования
  7. Props
  8. Смотри также
  9. QuotaWidgetMini
  10. Когда использовать
  11. Анатомия
  12. Примеры использования
  13. Props
  14. Смотри также
  15. QuotaWidgetCard
  16. Когда использовать
  17. Анатомия
  18. Примеры использования
  19. Props
  20. Смотри также

Quota

@cloud-ru/ds-uikit-product-quota — Виджеты квот проекта — выпадающий QuotaWidget, аккордеон QuotaWidgetMini и карточка квоты QuotaWidgetCard с прогрессом и состояниями loading/error.

Пакет @cloud-ru/ds-uikit-product-quota предоставляет три компонента для отображения квот проекта. Все три используют общую модель данных QuotaItem (name, limit, usage, remains, unitDisplayName) и общие состояния загрузки и ошибки.

  • QuotaWidget — кнопка-триггер с выпадающим списком карточек квот, для шапки продуктовых страниц.
  • QuotaWidgetMini — компактный аккордеон со списком квот, для сайдбаров и узких layout'ов.
  • QuotaWidgetCard — карточка одной квоты с прогресс-баром, tooltip-расшифровкой и состояниями loading / noData.

Карточки внутри QuotaWidget и QuotaWidgetMini — те же QuotaWidgetCard; исчерпанные квоты (remains <= 0) поднимаются в начало списка и подсчитываются в counter триггера.

Отдельно доступен QuotaWidgetContent — содержимое QuotaWidget без кнопки-триггера и выпадающего списка, для случаев, когда раскрытие даёт контейнер снаружи.

Установка

pnpm add @cloud-ru/ds-uikit-product-quota
import { QuotaWidget, QuotaWidgetMini, QuotaWidgetCard } from '@cloud-ru/ds-uikit-product-quota'

Figma

Все три компонента живут на одной странице Quota файла Product UI Kit. Ссылки на конкретные узлы — на страницах компонентов.

QuotaWidget

Кнопка-триггер с выпадающим списком карточек квот проекта — counter исчерпанных квот, ссылка на страницу квот и кнопка увеличения.

Кнопка «Квоты» с counter'ом исчерпанных квот, по клику открывающая Dropdown с шапкой проекта и сеткой карточек QuotaWidgetCard. Шапка содержит название проекта, ссылку на страницу квот (quotasUrl) и кнопку «Увеличить квоты» (при canEditQuota).

Когда использовать

  • Шапка продуктовой страницы или toolbar, где квоты — вторичная информация и раскрываются по требованию.

  • Нужен индикатор исчерпанных квот без постоянного места под список.

  • Узкий сайдбар, где список квот должен быть виден без портала:

    • используйте QuotaWidgetMini.
  • Одна конкретная квота на странице ресурса:

    • используйте QuotaWidgetCard.
  • ✅ Оборачивайте страницу в PortalContextProvider — контент рендерится в портал Dropdown.

  • ❌ Рендерить виджет без portal-контекста — выпадающий список не появится.

  • ✅ Переключайте error обратно после успешного onRefresh — кнопка повтора в состоянии ошибки.

  • ❌ Оставлять error без рабочего onRefresh — пользователь не сможет восстановить список.

Анатомия

Триггер

Button view='function' с label «Квоты» и chevron-иконкой; counter показывает число исчерпанных квот (remains <= 0). Внешний вид настраивается через buttonProps (size, appearance, label, fullWidth, disabled, className).

Шапка проекта

  • projectName — название проекта.
  • quotasUrl + onQuotasUrlClick — ссылка на страницу квот.
  • canEditQuota + onIncreaseQuotaClick — кнопка «Увеличить квоты».

Список квот

Сетка карточек QuotaWidgetCard. Исчерпанные квоты поднимаются в начало (отключается disableSorting). Состояния:

  • loading — skeleton-карточки.
  • error — блок ошибки с кнопкой повтора (onRefresh).

Контент без триггера — QuotaWidgetContent

Шапка проекта и сетка карточек без кнопки-триггера и без Dropdown. Нужен, когда раскрытие даёт контейнер снаружи — например sideBlock формы, который на mobile уже открывает BottomSheet. Принимает те же данные и состояния, что QuotaWidget.

На mobile QuotaWidget выносит шапку и кнопку «Увеличить квоты» в pinned-слоты title и footer листа, чтобы они не скроллились вместе с карточками. За это отвечают два пропа:

  • hideMobileHeader — не рендерить мобильную шапку внутри контента.
  • hideMobileIncreaseButton — не рендерить мобильную кнопку расширения внутри контента.

Оба влияют только на mobile-раскладку. Включайте их, когда сами кладёте заголовок и кнопку в слоты своего контейнера, иначе элементы отрисуются дважды.

Примеры использования

Базовый случай

Counter исчерпанных квот на триггере, сетка карточек в dropdown

import { QuotaItem, QuotaWidget } from '@cloud-ru/ds-uikit-product-quota';
import { useState } from 'react';

const QUOTAS: QuotaItem[] = [
  { name: 'vCPU', limit: 100, usage: 42, remains: 58, unitDisplayName: 'cores' },
  { name: 'RAM', limit: 256, usage: 230, remains: 26, unitDisplayName: 'GB' },
  { name: 'SSD', limit: 1000, usage: 1000, remains: 0, unitDisplayName: 'GB' },
  { name: 'Public IP', limit: 10, usage: 9, remains: 1, unitDisplayName: 'pcs' },
];

export function QuotaWidgetBasic() {
  const [loading, setLoading] = useState(false);

  const reload = () => {
    setLoading(true);
    setTimeout(() => setLoading(false), 800);
  };

  return (
    // В продукте виджет живёт у правого края страницы — dropdown прижат к правому краю триггера
    <div style={{ display: 'flex', justifyContent: 'flex-end', width: '100%' }}>
      <QuotaWidget
        quotas={QUOTAS}
        projectName='ml-platform-production'
        quotasUrl='#'
        canEditQuota={false}
        loading={loading}
        error={false}
        onRefresh={reload}
      />
    </div>
  );
}

Ошибка загрузки и повтор

error показывает блок ошибки; onRefresh переключает в loading и восстанавливает список

import { QuotaItem, QuotaWidget } from '@cloud-ru/ds-uikit-product-quota';
import { useState } from 'react';

const QUOTAS: QuotaItem[] = [
  { name: 'vCPU', limit: 100, usage: 42, remains: 58, unitDisplayName: 'cores' },
  { name: 'RAM', limit: 256, usage: 230, remains: 26, unitDisplayName: 'GB' },
];

export function QuotaWidgetError() {
  const [error, setError] = useState(true);
  const [loading, setLoading] = useState(false);

  const handleRefresh = () => {
    setLoading(true);
    setTimeout(() => {
      setLoading(false);
      setError(false);
    }, 800);
  };

  return (
    // В продукте виджет живёт у правого края страницы — dropdown прижат к правому краю триггера
    <div style={{ display: 'flex', justifyContent: 'flex-end', width: '100%' }}>
      <QuotaWidget
        quotas={QUOTAS}
        projectName='ml-platform-production'
        quotasUrl='#'
        canEditQuota={false}
        loading={loading}
        error={error}
        onRefresh={handleRefresh}
      />
    </div>
  );
}

Props

QuotaWidget

QuotaWidgetProps

PropTypeDefaultDescription
buttonPropsButtonProps—Свойства кнопки открытия виджета
canEditQuotaboolean—Флаг наличия прав на редактирование квот
data-test-idstring—
disableSortingboolean—Флаг отключения сортировки квот
errorboolean—Флаг ошибки при загрузке квот
loadingboolean—Флаг загрузки квот
onIncreaseQuotaClick(() => void)—Колбек нажатия на кнопку увеличения квот
onQuotasUrlClick(() => void)—Колбек клика по ссылке на страницу квот по проекту
onRefresh() => void—Колбек на обновление списка квот при ошибке
onWidgetOpen(() => void)—Колбек открытия виджета квот
projectNamestring—Название проекта, по которому отображаются квоты
quotasQuotaItem—Список квот для отображения
quotasUrlstring—Ссылка на страницу квот по проекту
skeletonRowCountnumber4Количество строк-заглушек, пока идёт загрузка.
Строка — это ряд сетки: в две колонки (desktop-дропдаун) она даёт две карточки,
в одну (mobile, аккордеон QuotaWidgetMini) — одну.

QuotaItem

PropTypeDefaultDescription
limitnumber—Лимит квоты
namestring—Название квоты
remainsnumber—Остаток квоты
unitDisplayNamestring—Единица измерения квоты
usagenumber—Потребление квоты

QuotaWidgetContent

QuotaWidgetContentProps

PropTypeDefaultDescription
canEditQuotaboolean—Флаг наличия прав на редактирование квот
data-test-idstring—
disableSortingboolean—Флаг отключения сортировки квот
errorboolean—Флаг ошибки при загрузке квот
hideMobileHeaderbooleanfalseНе рендерить мобильную шапку (её выносят в pinned-title контейнера, напр. BottomSheet).
На desktop не влияет.
hideMobileIncreaseButtonbooleanfalseНе рендерить мобильную кнопку расширения (её выносят в pinned-footer контейнера).
На desktop не влияет.
loadingboolean—Флаг загрузки квот
onIncreaseQuotaClick(() => void)—Колбек нажатия на кнопку увеличения квот
onQuotasUrlClick(() => void)—Колбек клика по ссылке на страницу квот по проекту
onRefresh() => void—Колбек на обновление списка квот при ошибке
onWidgetOpen(() => void)—Колбек открытия виджета квот
projectNamestring—Название проекта, по которому отображаются квоты
quotasQuotaItem—Список квот для отображения
quotasUrlstring—Ссылка на страницу квот по проекту
skeletonRowCountnumber4Количество строк-заглушек, пока идёт загрузка.
Строка — это ряд сетки: в две колонки (desktop-дропдаун) она даёт две карточки,
в одну (mobile, аккордеон QuotaWidgetMini) — одну.

QuotaItem

PropTypeDefaultDescription
limitnumber—Лимит квоты
namestring—Название квоты
remainsnumber—Остаток квоты
unitDisplayNamestring—Единица измерения квоты
usagenumber—Потребление квоты

Смотри также

  • QuotaWidgetMini — тот же список в аккордеоне без портала.
  • QuotaWidgetCard — карточка одной квоты.
  • Dropdown — нижележащий портальный примитив.

QuotaWidgetMini

Компактный аккордеон со списком квот проекта — counter исчерпанных квот в заголовке и кнопка увеличения квот.

Сворачиваемый блок на базе Accordion: заголовок «Квоты» с counter'ом исчерпанных квот и названием проекта в подзаголовке, внутри — вертикальный список карточек QuotaWidgetCard и кнопка «Увеличить квоты». Портал не используется — контент раскрывается в потоке документа.

Когда использовать

  • Сайдбары и узкие панели, где список квот должен раскрываться на месте, без overlay.

  • Mobile / adaptive layout'ы — аккордеон не требует позиционирования портала.

  • Шапка широкой страницы с раскрытием по клику:

    • используйте QuotaWidget.
  • ✅ Используйте defaultExpanded, если квоты — ключевой контент экрана и должны быть видны сразу.

  • ❌ Контролировать раскрытие снаружи — аккордеон uncontrolled, публичного controlled-API нет.

Анатомия

Заголовок

Accordion.CollapseBlockSecondary: title «Квоты», после него Counter appearance='critical' с числом исчерпанных квот (скрыт при loading / error), в подзаголовке — projectName с truncate.

Содержимое

  • Вертикальный список QuotaWidgetCard; исчерпанные квоты поднимаются в начало (disableSorting отключает).
  • loading — skeleton-карточки; error — блок ошибки с кнопкой повтора (onRefresh).
  • Кнопка «Увеличить квоты» (canEditQuota, onIncreaseQuotaClick).

Примеры использования

Раскрыт по умолчанию

defaultExpanded + counter исчерпанной квоты в заголовке

import { QuotaItem, QuotaWidgetMini } from '@cloud-ru/ds-uikit-product-quota';
import { useState } from 'react';

const QUOTAS: QuotaItem[] = [
  { name: 'SSD', limit: 1000, usage: 1000, remains: 0, unitDisplayName: 'GB' },
  { name: 'RAM', limit: 256, usage: 230, remains: 26, unitDisplayName: 'GB' },
  { name: 'vCPU', limit: 100, usage: 42, remains: 58, unitDisplayName: 'cores' },
];

export function QuotaWidgetMiniExpanded() {
  const [loading, setLoading] = useState(false);

  const reload = () => {
    setLoading(true);
    setTimeout(() => setLoading(false), 800);
  };

  return (
    <QuotaWidgetMini
      quotas={QUOTAS}
      projectName='ml-platform-production'
      canEditQuota={false}
      defaultExpanded
      loading={loading}
      error={false}
      onRefresh={reload}
    />
  );
}

Props

QuotaWidgetMiniProps

PropTypeDefaultDescription
canEditQuotaboolean—Флаг наличия прав на редактирование квот
data-test-idstring—
defaultExpandedboolean—Флаг раскрытия аккордиона по умолчанию
disableSortingboolean—Флаг отключения сортировки квот
errorboolean—Флаг ошибки при загрузке квот
loadingboolean—Флаг загрузки квот
onIncreaseQuotaClick(() => void)—Колбек нажатия на кнопку увеличения квот
onRefresh() => void—Колбек на обновление списка квот при ошибке
onWidgetOpen(() => void)—Колбек открытия виджета квот
projectNamestring—Название проекта, по которому отображаются квоты
quotasQuotaItem—Список квот для отображения
skeletonRowCountnumber4Количество строк-заглушек, пока идёт загрузка.
Строка — это ряд сетки: в две колонки (desktop-дропдаун) она даёт две карточки,
в одну (mobile, аккордеон QuotaWidgetMini) — одну.

QuotaItem

PropTypeDefaultDescription
limitnumber—Лимит квоты
namestring—Название квоты
remainsnumber—Остаток квоты
unitDisplayNamestring—Единица измерения квоты
usagenumber—Потребление квоты

Смотри также

  • QuotaWidget — выпадающий вариант для шапки страницы.
  • QuotaWidgetCard — карточка одной квоты.
  • Accordion — нижележащий примитив раскрытия.

QuotaWidgetCard

Карточка одной квоты — прогресс-бар потребления с цветовыми порогами, tooltip-расшифровка и состояния loading/noData.

Карточка одной квоты QuotaItem: название, остаток в единицах измерения, ProgressBar потребления и Tooltip с расшифровкой «лимит / потреблено / остаток». Используется внутри QuotaWidget и QuotaWidgetMini, но доступна и отдельно.

Когда использовать

  • Страница ресурса или дашборд, где нужно показать одну конкретную квоту.

  • Собственная раскладка квот, не покрываемая QuotaWidget / QuotaWidgetMini.

  • Список квот проекта целиком:

    • используйте QuotaWidget или QuotaWidgetMini.
  • ✅ Оборачивайте карточку в PortalContextProvider — tooltip рендерится в портал.

  • ❌ Передавать noData без onRefresh — состояние ошибки останется без кнопки восстановления.

Анатомия

Прогресс потребления

Цвет ProgressBar зависит от процента потребления (usage / limit):

  • < 70% — зелёный.
  • 70–90% — жёлтый.
  • >= 90% — красный; при remains <= 0 квота считается исчерпанной.

Состояния

  • loading — skeleton вместо значений.
  • noData — InfoBlock с текстом ошибки и кнопкой «Обновить» (onRefresh).

Примеры использования

Уровни потребления

Зелёный, жёлтый, красный пороги и исчерпанная квота

import { QuotaWidgetCard } from '@cloud-ru/ds-uikit-product-quota';

export function QuotaCardLevels() {
  return (
    <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
      <QuotaWidgetCard quota={{ name: 'Network', limit: 100, usage: 30, remains: 70, unitDisplayName: 'GB' }} />
      <QuotaWidgetCard quota={{ name: 'RAM', limit: 100, usage: 75, remains: 25, unitDisplayName: 'GB' }} />
      <QuotaWidgetCard quota={{ name: 'vCPU', limit: 100, usage: 95, remains: 5, unitDisplayName: 'cores' }} />
      <QuotaWidgetCard quota={{ name: 'SSD', limit: 100, usage: 100, remains: 0, unitDisplayName: 'GB' }} />
    </div>
  );
}

Loading

import { QuotaWidgetCard } from '@cloud-ru/ds-uikit-product-quota';

export function QuotaCardLoading() {
  return (
    <QuotaWidgetCard loading quota={{ name: 'Network', limit: 100, usage: 30, remains: 70, unitDisplayName: 'GB' }} />
  );
}

Нет данных и повтор

noData показывает InfoBlock; onRefresh возвращает карточку к данным

import { QuotaWidgetCard } from '@cloud-ru/ds-uikit-product-quota';
import { useState } from 'react';

const QUOTA = { name: 'Network', limit: 100, usage: 30, remains: 70, unitDisplayName: 'GB' };

export function QuotaCardNoData() {
  const [noData, setNoData] = useState(true);
  const [loading, setLoading] = useState(false);

  const handleRefresh = () => {
    setLoading(true);
    setNoData(false);
    setTimeout(() => setLoading(false), 800);
  };

  return <QuotaWidgetCard quota={QUOTA} noData={noData} loading={loading} onRefresh={handleRefresh} />;
}

Props

QuotaWidgetCardProps

PropTypeDefaultDescription
data-test-idstring—
loadingbooleanfalseСостояние загрузки (Figma: loading=true)
noDatabooleanfalseСостояние «не удалось загрузить данные» (Figma: noData=true)
onRefresh(() => void)—Колбек кнопки «Обновить» в состоянии noData
quotaQuotaItem—Отображаемая квота

QuotaItem

PropTypeDefaultDescription
limitnumber—Лимит квоты
namestring—Название квоты
remainsnumber—Остаток квоты
unitDisplayNamestring—Единица измерения квоты
usagenumber—Потребление квоты

Смотри также

  • QuotaWidget — выпадающий список карточек.
  • QuotaWidgetMini — аккордеон с карточками.
  • ProgressBar — нижележащий индикатор потребления.

版本与发布记录

@cloud-ru/ds-uikit-product-quota 共发布 147 个版本,首次发布于 2026/08/18;过去 12 个月发布了 147 个版本。

版本发布日期距今
2.1.0latest2026/11/11今天
2.0.5-preview-e8fe6b56.0preview2026/11/11今天
2.0.5-preview-c0e895ed.02026/11/11今天
2.0.5-preview-90b10112.02026/11/11今天
2.0.5-preview-fd7dd437.02026/11/101 天前
2.0.5-preview-9a75a2a9.02026/11/101 天前

关于 @cloud-ru/ds-uikit-product-quota 的常见问题

@cloud-ru/ds-uikit-product-quota 是什么?

Виджеты квот проекта — выпадающий QuotaWidget, аккордеон QuotaWidgetMini и карточка квоты QuotaWidgetCard с прогрессом и состояниями loading/error.

如何安装 @cloud-ru/ds-uikit-product-quota?

在项目目录运行 npm install @cloud-ru/ds-uikit-product-quota,或使用 pnpm add / yarn add / bun add。

@cloud-ru/ds-uikit-product-quota 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cloud-ru/ds-uikit-product-quota 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cloud-ru/ds-uikit-product-quota 可以商用吗?

@cloud-ru/ds-uikit-product-quota 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@cloud-ru/ds-uikit-product-quota 的下载量有多少?

根据 npm 官方下载统计,@cloud-ru/ds-uikit-product-quota 在 2026/10/10 – 2026/11/08 这 30 天内被下载 4,640 次,日均约 155 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cloud-ru/ds-uikit-product-quota 还在维护吗?

最新版本 2.1.0 发布于 2026/11/11(今天);至今共发布 147 个版本,其中过去 12 个月发布了 147 个;首次发布于 2026/08/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。