@iskra-ui/dci-react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENCE.md +79 -0
- package/dist/components/ApiKeyModal/ApiKeyModal.d.ts +27 -0
- package/dist/components/ApiKeyModal/ApiKeyModal.d.ts.map +1 -0
- package/dist/components/CliRow/CliRow.d.ts +16 -0
- package/dist/components/CliRow/CliRow.d.ts.map +1 -0
- package/dist/components/DeviceCard/DeviceCard.d.ts +27 -0
- package/dist/components/DeviceCard/DeviceCard.d.ts.map +1 -0
- package/dist/components/DriftToast/DriftToast.d.ts +18 -0
- package/dist/components/DriftToast/DriftToast.d.ts.map +1 -0
- package/dist/components/FleetPulse/FleetPulse.d.ts +27 -0
- package/dist/components/FleetPulse/FleetPulse.d.ts.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +352 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +2 -0
- package/package.json +58 -0
package/LICENCE.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Лицензии
|
|
2
|
+
|
|
3
|
+
Документ фиксирует правовой статус кода дизайн-системы **Искра.DCI** и сторонних компонентов, которые **поставляются потребителям** вместе с npm-пакетами `@iskra-ui/*`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Пакеты `@iskra-ui/*`
|
|
8
|
+
|
|
9
|
+
| Пакет | Статус |
|
|
10
|
+
| --------------------- | ---------------------------------------------- |
|
|
11
|
+
| `@iskra-ui/tokens` | Проприетарное ПО |
|
|
12
|
+
| `@iskra-ui/styles` | Проприетарное ПО + сторонние шрифты (см. ниже) |
|
|
13
|
+
| `@iskra-ui/icons` | Проприетарное ПО |
|
|
14
|
+
| `@iskra-ui/core` | Проприетарное ПО |
|
|
15
|
+
| `@iskra-ui/react` | Проприетарное ПО |
|
|
16
|
+
| `@iskra-ui/vue` | Проприетарное ПО |
|
|
17
|
+
| `@iskra-ui/dci-react` | Проприетарное ПО |
|
|
18
|
+
|
|
19
|
+
Исходный код, дизайн-токены, компоненты, документация и торговые обозначения **Искра.DCI** / **ИСКРА.DCI** принадлежат правообладателю платформы. Все права защищены.
|
|
20
|
+
|
|
21
|
+
Пакеты публикуются в публичном npm-реестре (`publishConfig.access: public`). Использование, копирование, распространение и модификация **вне условий, согласованных с правообладателем**, запрещены.
|
|
22
|
+
|
|
23
|
+
Приватные пакеты монорепозитория (`@iskra-ui/eslint-config`, `@iskra-ui/tsconfig`, `@iskra-ui/docs-react`) распространяются только внутри репозитория и не публикуются в npm.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Сторонние компоненты в составе поставки
|
|
28
|
+
|
|
29
|
+
### Шрифты (`@iskra-ui/styles`)
|
|
30
|
+
|
|
31
|
+
В бандл `@iskra-ui/styles` встроены variable-шрифты (self-hosted, без CDN):
|
|
32
|
+
|
|
33
|
+
| Шрифт | Файл | Лицензия |
|
|
34
|
+
| ---------------------------------------------------- | ---------------------------------- | --------------------------------------------------------- |
|
|
35
|
+
| [Inter](https://rsms.me/inter/) | `Inter-VariableFont_opsz_wght.ttf` | [SIL Open Font License 1.1](https://openfontlicense.org/) |
|
|
36
|
+
| [JetBrains Mono](https://www.jetbrains.com/lp/mono/) | `JetBrainsMono_wght_.ttf` | [SIL Open Font License 1.1](https://openfontlicense.org/) |
|
|
37
|
+
|
|
38
|
+
Шрифты копируются в `packages/styles/dist/fonts/` при сборке пакета. При распространении производных продуктов необходимо сохранять уведомления OFL для этих файлов.
|
|
39
|
+
|
|
40
|
+
**Краткое условие OFL 1.1:** шрифты можно использовать, изучать, модифицировать и распространять при условии, что производные шрифты не продаются отдельно и что уведомление об авторских правах и лицензии OFL сохраняется в составе дистрибутива.
|
|
41
|
+
|
|
42
|
+
### Иконки (`@iskra-ui/icons`)
|
|
43
|
+
|
|
44
|
+
Набор `@iskra-ui/icons` — **оригинальная SVG-разметка** Искра.DCI (16×16, stroke 1.5px), нарисованная под геометрию outline-иконок, принятую в бренде.
|
|
45
|
+
|
|
46
|
+
Геометрия согласована со стилем:
|
|
47
|
+
|
|
48
|
+
| Источник | Лицензия | Примечание |
|
|
49
|
+
| --------------------------------------------- | -------- | ---------------------------------------------------------------------- |
|
|
50
|
+
| [Feather Icons](https://feathericons.com/) | MIT | Референс по stroke и сетке; глифы в репозитории не копируются дословно |
|
|
51
|
+
| [Heroicons](https://heroicons.com/) (outline) | MIT | Допустимый заменитель при отсутствии глифа в наборе |
|
|
52
|
+
|
|
53
|
+
MIT-лицензии Feather Icons и Heroicons **не распространяются** на код `@iskra-ui/icons`, но указаны как происхождение визуального языка. При публикации открытых форков или выноса иконок в отдельный OSS-пакет — сверьтесь с юридической службой правообладателя.
|
|
54
|
+
|
|
55
|
+
### Инструменты разработки (не входят в npm-поставку)
|
|
56
|
+
|
|
57
|
+
Зависимости dev/build (React, Vue, Vite, Storybook, ESLint, Turbo, Changesets и др.) подчиняются лицензиям соответствующих проектов. Они **не включаются** в publishable-артефакты `@iskra-ui/*` и в этом документе не перечисляются.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Торговые марки
|
|
62
|
+
|
|
63
|
+
**Искра**, **Искра.DCI**, **ИСКРА.DCI**, логотип-искра и маскот **Бит** — элементы бренда платформы. Их использование вне продуктов правообладателя регулируется отдельно от лицензии на исходный код.
|
|
64
|
+
|
|
65
|
+
Названия **React**, **Vue**, **pnpm**, **Storybook** и других сторонних проектов принадлежат их владельцам.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Вопросы по лицензированию
|
|
70
|
+
|
|
71
|
+
По условиям использования пакетов `@iskra-ui/*`, white-label брендингу и включению компонентов в сторонние продукты обращайтесь к правообладателю платформы Искра.DCI.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## См. также
|
|
76
|
+
|
|
77
|
+
- [README.md](README.md) — обзор монорепозитория
|
|
78
|
+
- [docs/PACKAGES.md](docs/PACKAGES.md) — состав поставки пакетов
|
|
79
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) — разработка и релизы
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import './ApiKeyModal.css';
|
|
2
|
+
export interface ApiKeyScope {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ApiKeyDraft {
|
|
8
|
+
name: string;
|
|
9
|
+
scopes: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface ApiKeyModalProps {
|
|
12
|
+
open: boolean;
|
|
13
|
+
onClose: () => void;
|
|
14
|
+
/** Called with the validated draft when the user confirms creation. */
|
|
15
|
+
onCreate: (draft: ApiKeyDraft) => void;
|
|
16
|
+
scopes?: ApiKeyScope[];
|
|
17
|
+
title?: string;
|
|
18
|
+
submitLabel?: string;
|
|
19
|
+
cancelLabel?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* ApiKeyModal — domain dialog for minting a scoped API key. Built on the
|
|
23
|
+
* foundation `Modal`, `TextField`, `Checkbox` and `Button`. Submit is disabled
|
|
24
|
+
* until a name and at least one scope are provided.
|
|
25
|
+
*/
|
|
26
|
+
export declare function ApiKeyModal({ open, onClose, onCreate, scopes, title, submitLabel, cancelLabel, }: ApiKeyModalProps): import("react").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=ApiKeyModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiKeyModal.d.ts","sourceRoot":"","sources":["../../../src/components/ApiKeyModal/ApiKeyModal.tsx"],"names":[],"mappings":"AAEA,OAAO,mBAAmB,CAAC;AAE3B,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,uEAAuE;IACvE,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAQD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,MAAuB,EACvB,KAAwB,EACxB,WAA4B,EAC5B,WAAsB,GACvB,EAAE,gBAAgB,+BAoElB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import './CliRow.css';
|
|
2
|
+
export interface CliRowProps {
|
|
3
|
+
/** The command string to display and copy. */
|
|
4
|
+
command: string;
|
|
5
|
+
/** Custom copy handler. Defaults to the Clipboard API. */
|
|
6
|
+
onCopy?: (command: string) => void;
|
|
7
|
+
copyLabel?: string;
|
|
8
|
+
copiedLabel?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* CliRow — monospace command row with a copy-to-clipboard affordance. Used to
|
|
13
|
+
* surface the equivalent API/CLI call for an action performed in the UI.
|
|
14
|
+
*/
|
|
15
|
+
export declare function CliRow({ command, onCopy, copyLabel, copiedLabel, className, }: CliRowProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=CliRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CliRow.d.ts","sourceRoot":"","sources":["../../../src/components/CliRow/CliRow.tsx"],"names":[],"mappings":"AAEA,OAAO,cAAc,CAAC;AAEtB,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,MAAM,EACN,SAAkB,EAClB,WAAsB,EACtB,SAAS,GACV,EAAE,WAAW,+BA6Bb"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type CardProps } from '@iskra-ui/react';
|
|
2
|
+
import './DeviceCard.css';
|
|
3
|
+
export type DeviceStatus = 'sync' | 'drift' | 'error' | 'offline';
|
|
4
|
+
export interface DeviceCardProps extends Omit<CardProps, 'children' | 'title'> {
|
|
5
|
+
/** Device hostname, e.g. `spine-01.msk`. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Management IP. */
|
|
8
|
+
ip: string;
|
|
9
|
+
status: DeviceStatus;
|
|
10
|
+
/** Sparkline metric label, e.g. `CPU · 24 ч`. */
|
|
11
|
+
metricLabel: string;
|
|
12
|
+
/** Formatted metric value, e.g. `88%`. */
|
|
13
|
+
metricValue: string;
|
|
14
|
+
/** Render the metric value + bars in the alert (warn) colour. */
|
|
15
|
+
metricAlert?: boolean;
|
|
16
|
+
/** Normalised sparkline samples in the 0..1 range. */
|
|
17
|
+
sparkline?: number[];
|
|
18
|
+
tags?: string[];
|
|
19
|
+
onSelect?: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* DeviceCard — fleet device tile with status, a single configurable sparkline
|
|
23
|
+
* metric and tags. Built on the foundation `Card`. Set `onSelect` to make it an
|
|
24
|
+
* accessible button-like surface.
|
|
25
|
+
*/
|
|
26
|
+
export declare function DeviceCard({ name, ip, status, metricLabel, metricValue, metricAlert, sparkline, tags, onSelect, className, ...rest }: DeviceCardProps): import("react").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=DeviceCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceCard.d.ts","sourceRoot":"","sources":["../../../src/components/DeviceCard/DeviceCard.tsx"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,kBAAkB,CAAC;AAE1B,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AASlE,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC;IAC5E,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;IACrB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,EAAE,EACF,MAAM,EACN,WAAW,EACX,WAAW,EACX,WAAmB,EACnB,SAAc,EACd,IAAS,EACT,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACR,EAAE,eAAe,+BAsDjB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import './DriftToast.css';
|
|
3
|
+
export type DriftToastVariant = 'drift' | 'ok' | 'error' | 'info';
|
|
4
|
+
export interface DriftToastProps {
|
|
5
|
+
variant?: DriftToastVariant;
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
onClose?: () => void;
|
|
9
|
+
closeLabel?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* DriftToast — Искра.DCI notification with a left status stripe, tuned for the
|
|
14
|
+
* drift/sync/error/info lifecycle. Drift and error announce assertively
|
|
15
|
+
* (`role="alert"`); ok/info are polite (`role="status"`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function DriftToast({ variant, title, description, onClose, closeLabel, className, }: DriftToastProps): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=DriftToast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DriftToast.d.ts","sourceRoot":"","sources":["../../../src/components/DriftToast/DriftToast.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,kBAAkB,CAAC;AAE1B,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC;AAgBlE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAgB,EAChB,KAAK,EACL,WAAW,EACX,OAAO,EACP,UAAsB,EACtB,SAAS,GACV,EAAE,eAAe,+BAyBjB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import './FleetPulse.css';
|
|
2
|
+
export type IssueSeverity = 'error' | 'drift';
|
|
3
|
+
export interface FleetIssue {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
severity: IssueSeverity;
|
|
8
|
+
actionLabel?: string;
|
|
9
|
+
onAction?: () => void;
|
|
10
|
+
}
|
|
11
|
+
export interface FleetPulseProps {
|
|
12
|
+
/** Percentage of the fleet in sync (0–100). */
|
|
13
|
+
percent: number;
|
|
14
|
+
issues?: FleetIssue[];
|
|
15
|
+
label?: string;
|
|
16
|
+
defaultOpen?: boolean;
|
|
17
|
+
open?: boolean;
|
|
18
|
+
onOpenChange?: (open: boolean) => void;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* FleetPulse — interactive sync ring summarising fleet health that expands into
|
|
23
|
+
* a list of problem devices with inline remediation actions. Controlled or
|
|
24
|
+
* uncontrolled via `open`/`defaultOpen`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function FleetPulse({ percent, issues, label, defaultOpen, open, onOpenChange, className, }: FleetPulseProps): import("react").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=FleetPulse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FleetPulse.d.ts","sourceRoot":"","sources":["../../../src/components/FleetPulse/FleetPulse.tsx"],"names":[],"mappings":"AAEA,OAAO,kBAAkB,CAAC;AAE1B,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,MAAW,EACX,KAAuB,EACvB,WAAmB,EACnB,IAAI,EACJ,YAAY,EACZ,SAAS,GACV,EAAE,eAAe,+BAsFjB"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react"),t=require("@iskra-ui/react"),n=require("react/jsx-runtime");var r={sync:`Sync`,drift:`Drift`,error:`Error`,offline:`Offline`};function i({name:e,ip:i,status:a,metricLabel:o,metricValue:s,metricAlert:c=!1,sparkline:l=[],tags:u=[],onSelect:d,className:f,...p}){let m=typeof d==`function`;return(0,n.jsxs)(t.Card,{padding:`s`,interactive:m,className:[`dci-device`,m&&`is-clickable`,f].filter(Boolean).join(` `),onClick:m?d:void 0,onKeyDown:m?e=>{m&&(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),d())}:void 0,role:m?`button`:void 0,"aria-label":m?`${e} — ${r[a]}`:void 0,...p,children:[(0,n.jsxs)(`div`,{className:`dci-device-top`,children:[(0,n.jsx)(`span`,{className:`dci-device-dot s-${a}`,"aria-hidden":`true`}),(0,n.jsx)(`span`,{className:`dci-device-name`,children:e}),(0,n.jsx)(`span`,{className:`dci-device-status s-${a}`,children:r[a]})]}),(0,n.jsx)(`div`,{className:`dci-device-ip`,children:i}),(0,n.jsxs)(`div`,{className:`dci-device-metahd`,children:[(0,n.jsx)(`span`,{className:`dci-device-metric-label`,children:o}),(0,n.jsx)(`span`,{className:`dci-device-metric-value${c?` is-alert`:``}`,children:s})]}),l.length>0&&(0,n.jsx)(`div`,{className:`dci-device-spark`,"aria-hidden":`true`,children:l.map((e,t)=>(0,n.jsx)(`span`,{className:`dci-device-bar${c?` is-alert`:``}`,style:{height:`${Math.max(0,Math.min(1,e))*100}%`}},t))}),u.length>0&&(0,n.jsx)(`div`,{className:`dci-device-tags`,children:u.map(e=>(0,n.jsx)(`span`,{className:`dci-device-tag`,children:e},e))})]})}var a=22,o=2*Math.PI*a;function s({percent:r,issues:i=[],label:s=`Fleet in Sync`,defaultOpen:c=!1,open:l,onOpenChange:u,className:d}){let f=l!=null,[p,m]=(0,e.useState)(c),h=f?l:p,g=(0,e.useId)(),_=Math.max(0,Math.min(100,r)),v=_/100*o,y=i.length>0;return(0,n.jsxs)(`div`,{className:[`dci-pulse-panel`,h&&`is-open`,d].filter(Boolean).join(` `),children:[(0,n.jsxs)(`button`,{type:`button`,className:`dci-pulse-head`,onClick:()=>{let e=!h;f||m(e),u?.(e)},"aria-expanded":h,"aria-controls":y?g:void 0,children:[(0,n.jsxs)(`svg`,{className:`dci-pulse-ring`,viewBox:`0 0 56 56`,"aria-hidden":`true`,children:[(0,n.jsx)(`circle`,{cx:`28`,cy:`28`,r:a,fill:`none`,stroke:`var(--line, #30363d)`,strokeWidth:`4`}),(0,n.jsx)(`circle`,{cx:`28`,cy:`28`,r:a,fill:`none`,stroke:`var(--accent, #00ffc2)`,strokeWidth:`4`,strokeDasharray:`${v} ${o-v}`,strokeLinecap:`round`,transform:`rotate(-90 28 28)`})]}),(0,n.jsxs)(`span`,{children:[(0,n.jsxs)(`span`,{className:`dci-pulse-pct`,children:[_,`%`]}),(0,n.jsx)(`span`,{className:`dci-pulse-label`,children:s}),y&&(0,n.jsxs)(`span`,{className:`dci-pulse-sub`,children:[(0,n.jsx)(`b`,{children:i.length}),` устройств требуют внимания — нажмите, чтобы развернуть`]})]}),(0,n.jsx)(`span`,{className:`dci-pulse-chev`,"aria-hidden":`true`,children:(0,n.jsx)(t.Icon,{name:`chevron-down`,size:16})})]}),y&&h&&(0,n.jsxs)(`div`,{className:`dci-pulse-issues`,id:g,children:[(0,n.jsxs)(`div`,{className:`dci-pulse-issues-hd`,children:[`Проблемные устройства · `,i.length]}),i.map(e=>(0,n.jsxs)(`div`,{className:`dci-pulse-row`,children:[(0,n.jsx)(`span`,{className:`dci-pulse-row-dot sev-${e.severity}`,"aria-hidden":`true`}),(0,n.jsx)(`span`,{className:`dci-pulse-row-name`,children:e.name}),(0,n.jsx)(`span`,{className:`dci-pulse-row-reason`,children:e.reason}),(0,n.jsx)(t.Badge,{variant:e.severity===`error`?`error`:`warning`,size:`s`,children:e.severity===`error`?`Error`:`Drift`}),e.actionLabel&&(0,n.jsx)(t.Button,{variant:`outline`,size:`s`,onClick:e.onAction,iconBefore:(0,n.jsx)(t.Icon,{name:`sync`,size:13}),children:e.actionLabel})]},e.id))]})]})}function c({command:r,onCopy:i,copyLabel:a=`Copy`,copiedLabel:o=`Copied`,className:s}){let[c,l]=(0,e.useState)(!1);return(0,n.jsxs)(`div`,{className:[`dci-cli`,s].filter(Boolean).join(` `),children:[(0,n.jsx)(`span`,{className:`dci-cli-icon`,"aria-hidden":`true`,children:`</>`}),(0,n.jsx)(`code`,{className:`dci-cli-text`,children:r}),(0,n.jsx)(t.Button,{variant:`outline`,size:`s`,onClick:()=>{i?i(r):typeof navigator<`u`&&navigator.clipboard&&navigator.clipboard.writeText(r),l(!0),setTimeout(()=>l(!1),1500)},iconBefore:(0,n.jsx)(t.Icon,{name:c?`check`:`copy`,size:13}),children:c?o:a})]})}var l={drift:`warning`,ok:`check-circle`,error:`x-circle`,info:`info`},u={drift:`alert`,ok:`status`,error:`alert`,info:`status`};function d({variant:e=`info`,title:r,description:i,onClose:a,closeLabel:o=`Закрыть`,className:s}){return(0,n.jsxs)(`div`,{className:[`dci-toast`,`v-${e}`,s].filter(Boolean).join(` `),role:u[e],children:[(0,n.jsx)(`span`,{className:`dci-toast-icon`,"aria-hidden":`true`,children:(0,n.jsx)(t.Icon,{name:l[e],size:11})}),(0,n.jsxs)(`div`,{className:`dci-toast-body`,children:[(0,n.jsx)(`div`,{className:`dci-toast-title`,children:r}),i&&(0,n.jsx)(`div`,{className:`dci-toast-desc`,children:i})]}),a&&(0,n.jsx)(t.IconButton,{className:`dci-toast-close`,variant:`ghost`,size:`s`,"aria-label":o,onClick:a,icon:(0,n.jsx)(t.Icon,{name:`close`,size:13})})]})}var f=[{id:`devices:read`,name:`devices:read`,description:`Чтение состояния устройств`},{id:`devices:write`,name:`devices:write`,description:`Применение конфигураций и sync`},{id:`metrics:read`,name:`metrics:read`,description:`Доступ к метрикам и спарклайнам`}];function p({open:r,onClose:i,onCreate:a,scopes:o=f,title:s=`Новый API-ключ`,submitLabel:c=`Создать ключ`,cancelLabel:l=`Отмена`}){let[u,d]=(0,e.useState)(``),[p,m]=(0,e.useState)({}),h=(0,e.useMemo)(()=>o.filter(e=>p[e.id]).map(e=>e.id),[o,p]),g=u.trim().length>0&&h.length>0,_=()=>{d(``),m({})},v=()=>{_(),i()};return(0,n.jsx)(t.Modal,{open:r,onClose:v,title:s,description:`Ключ будет показан один раз после создания.`,size:`m`,footer:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.Button,{variant:`ghost`,onClick:v,children:l}),(0,n.jsx)(t.Button,{variant:`primary`,onClick:()=>{g&&(a({name:u.trim(),scopes:h}),_())},disabled:!g,children:c})]}),children:(0,n.jsxs)(`div`,{className:`dci-apikey-form`,children:[(0,n.jsx)(t.TextField,{label:`Название ключа`,placeholder:`например, ci-deploy-bot`,required:!0,value:u,onChange:e=>d(e.target.value)}),(0,n.jsxs)(`fieldset`,{className:`dci-apikey-scopes`,children:[(0,n.jsx)(`legend`,{className:`dci-apikey-scopes-legend`,children:`Права доступа`}),o.map(e=>(0,n.jsx)(`div`,{className:`dci-apikey-scope`,children:(0,n.jsx)(t.Checkbox,{checked:!!p[e.id],onChange:t=>m(n=>({...n,[e.id]:t.target.checked})),label:(0,n.jsx)(`span`,{className:`dci-apikey-scope-name`,children:e.name}),description:e.description})},e.id))]})]})})}exports.ApiKeyModal=p,exports.CliRow=c,exports.DeviceCard=i,exports.DriftToast=d,exports.FleetPulse=s;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/components/DeviceCard/DeviceCard.tsx","../src/components/FleetPulse/FleetPulse.tsx","../src/components/CliRow/CliRow.tsx","../src/components/DriftToast/DriftToast.tsx","../src/components/ApiKeyModal/ApiKeyModal.tsx"],"sourcesContent":["import { type KeyboardEvent } from 'react';\nimport { Card, type CardProps } from '@iskra-ui/react';\nimport './DeviceCard.css';\n\nexport type DeviceStatus = 'sync' | 'drift' | 'error' | 'offline';\n\nconst STATUS_LABEL: Record<DeviceStatus, string> = {\n sync: 'Sync',\n drift: 'Drift',\n error: 'Error',\n offline: 'Offline',\n};\n\nexport interface DeviceCardProps extends Omit<CardProps, 'children' | 'title'> {\n /** Device hostname, e.g. `spine-01.msk`. */\n name: string;\n /** Management IP. */\n ip: string;\n status: DeviceStatus;\n /** Sparkline metric label, e.g. `CPU · 24 ч`. */\n metricLabel: string;\n /** Formatted metric value, e.g. `88%`. */\n metricValue: string;\n /** Render the metric value + bars in the alert (warn) colour. */\n metricAlert?: boolean;\n /** Normalised sparkline samples in the 0..1 range. */\n sparkline?: number[];\n tags?: string[];\n onSelect?: () => void;\n}\n\n/**\n * DeviceCard — fleet device tile with status, a single configurable sparkline\n * metric and tags. Built on the foundation `Card`. Set `onSelect` to make it an\n * accessible button-like surface.\n */\nexport function DeviceCard({\n name,\n ip,\n status,\n metricLabel,\n metricValue,\n metricAlert = false,\n sparkline = [],\n tags = [],\n onSelect,\n className,\n ...rest\n}: DeviceCardProps) {\n const clickable = typeof onSelect === 'function';\n const onKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (clickable && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n onSelect!();\n }\n };\n\n return (\n <Card\n padding=\"s\"\n interactive={clickable}\n className={['dci-device', clickable && 'is-clickable', className].filter(Boolean).join(' ')}\n onClick={clickable ? onSelect : undefined}\n onKeyDown={clickable ? onKeyDown : undefined}\n role={clickable ? 'button' : undefined}\n aria-label={clickable ? `${name} — ${STATUS_LABEL[status]}` : undefined}\n {...rest}\n >\n <div className=\"dci-device-top\">\n <span className={`dci-device-dot s-${status}`} aria-hidden=\"true\" />\n <span className=\"dci-device-name\">{name}</span>\n <span className={`dci-device-status s-${status}`}>{STATUS_LABEL[status]}</span>\n </div>\n <div className=\"dci-device-ip\">{ip}</div>\n <div className=\"dci-device-metahd\">\n <span className=\"dci-device-metric-label\">{metricLabel}</span>\n <span className={`dci-device-metric-value${metricAlert ? ' is-alert' : ''}`}>\n {metricValue}\n </span>\n </div>\n {sparkline.length > 0 && (\n <div className=\"dci-device-spark\" aria-hidden=\"true\">\n {sparkline.map((v, i) => (\n <span\n key={i}\n className={`dci-device-bar${metricAlert ? ' is-alert' : ''}`}\n style={{ height: `${Math.max(0, Math.min(1, v)) * 100}%` }}\n />\n ))}\n </div>\n )}\n {tags.length > 0 && (\n <div className=\"dci-device-tags\">\n {tags.map((t) => (\n <span key={t} className=\"dci-device-tag\">\n {t}\n </span>\n ))}\n </div>\n )}\n </Card>\n );\n}\n","import { useId, useState } from 'react';\nimport { Badge, Button, Icon } from '@iskra-ui/react';\nimport './FleetPulse.css';\n\nexport type IssueSeverity = 'error' | 'drift';\n\nexport interface FleetIssue {\n id: string;\n name: string;\n reason: string;\n severity: IssueSeverity;\n actionLabel?: string;\n onAction?: () => void;\n}\n\nexport interface FleetPulseProps {\n /** Percentage of the fleet in sync (0–100). */\n percent: number;\n issues?: FleetIssue[];\n label?: string;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n className?: string;\n}\n\nconst RADIUS = 22;\nconst CIRC = 2 * Math.PI * RADIUS;\n\n/**\n * FleetPulse — interactive sync ring summarising fleet health that expands into\n * a list of problem devices with inline remediation actions. Controlled or\n * uncontrolled via `open`/`defaultOpen`.\n */\nexport function FleetPulse({\n percent,\n issues = [],\n label = 'Fleet in Sync',\n defaultOpen = false,\n open,\n onOpenChange,\n className,\n}: FleetPulseProps) {\n const controlled = open != null;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isOpen = controlled ? open : internalOpen;\n const issuesId = useId();\n\n const pct = Math.max(0, Math.min(100, percent));\n const dash = (pct / 100) * CIRC;\n const hasIssues = issues.length > 0;\n\n const toggle = () => {\n const next = !isOpen;\n if (!controlled) setInternalOpen(next);\n onOpenChange?.(next);\n };\n\n return (\n <div className={['dci-pulse-panel', isOpen && 'is-open', className].filter(Boolean).join(' ')}>\n <button\n type=\"button\"\n className=\"dci-pulse-head\"\n onClick={toggle}\n aria-expanded={isOpen}\n aria-controls={hasIssues ? issuesId : undefined}\n >\n <svg className=\"dci-pulse-ring\" viewBox=\"0 0 56 56\" aria-hidden=\"true\">\n <circle\n cx=\"28\"\n cy=\"28\"\n r={RADIUS}\n fill=\"none\"\n stroke=\"var(--line, #30363d)\"\n strokeWidth=\"4\"\n />\n <circle\n cx=\"28\"\n cy=\"28\"\n r={RADIUS}\n fill=\"none\"\n stroke=\"var(--accent, #00ffc2)\"\n strokeWidth=\"4\"\n strokeDasharray={`${dash} ${CIRC - dash}`}\n strokeLinecap=\"round\"\n transform=\"rotate(-90 28 28)\"\n />\n </svg>\n <span>\n <span className=\"dci-pulse-pct\">{pct}%</span>\n <span className=\"dci-pulse-label\">{label}</span>\n {hasIssues && (\n <span className=\"dci-pulse-sub\">\n <b>{issues.length}</b> устройств требуют внимания — нажмите, чтобы развернуть\n </span>\n )}\n </span>\n <span className=\"dci-pulse-chev\" aria-hidden=\"true\">\n <Icon name=\"chevron-down\" size={16} />\n </span>\n </button>\n {hasIssues && isOpen && (\n <div className=\"dci-pulse-issues\" id={issuesId}>\n <div className=\"dci-pulse-issues-hd\">Проблемные устройства · {issues.length}</div>\n {issues.map((issue) => (\n <div className=\"dci-pulse-row\" key={issue.id}>\n <span className={`dci-pulse-row-dot sev-${issue.severity}`} aria-hidden=\"true\" />\n <span className=\"dci-pulse-row-name\">{issue.name}</span>\n <span className=\"dci-pulse-row-reason\">{issue.reason}</span>\n <Badge variant={issue.severity === 'error' ? 'error' : 'warning'} size=\"s\">\n {issue.severity === 'error' ? 'Error' : 'Drift'}\n </Badge>\n {issue.actionLabel && (\n <Button\n variant=\"outline\"\n size=\"s\"\n onClick={issue.onAction}\n iconBefore={<Icon name=\"sync\" size={13} />}\n >\n {issue.actionLabel}\n </Button>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { Button, Icon } from '@iskra-ui/react';\nimport './CliRow.css';\n\nexport interface CliRowProps {\n /** The command string to display and copy. */\n command: string;\n /** Custom copy handler. Defaults to the Clipboard API. */\n onCopy?: (command: string) => void;\n copyLabel?: string;\n copiedLabel?: string;\n className?: string;\n}\n\n/**\n * CliRow — monospace command row with a copy-to-clipboard affordance. Used to\n * surface the equivalent API/CLI call for an action performed in the UI.\n */\nexport function CliRow({\n command,\n onCopy,\n copyLabel = 'Copy',\n copiedLabel = 'Copied',\n className,\n}: CliRowProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = () => {\n if (onCopy) {\n onCopy(command);\n } else if (typeof navigator !== 'undefined' && navigator.clipboard) {\n void navigator.clipboard.writeText(command);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n\n return (\n <div className={['dci-cli', className].filter(Boolean).join(' ')}>\n <span className=\"dci-cli-icon\" aria-hidden=\"true\">\n </>\n </span>\n <code className=\"dci-cli-text\">{command}</code>\n <Button\n variant=\"outline\"\n size=\"s\"\n onClick={handleCopy}\n iconBefore={<Icon name={copied ? 'check' : 'copy'} size={13} />}\n >\n {copied ? copiedLabel : copyLabel}\n </Button>\n </div>\n );\n}\n","import { type ReactNode } from 'react';\nimport { IconButton, Icon, type IconName } from '@iskra-ui/react';\nimport './DriftToast.css';\n\nexport type DriftToastVariant = 'drift' | 'ok' | 'error' | 'info';\n\nconst ICON: Record<DriftToastVariant, IconName> = {\n drift: 'warning',\n ok: 'check-circle',\n error: 'x-circle',\n info: 'info',\n};\n\nconst ROLE: Record<DriftToastVariant, 'alert' | 'status'> = {\n drift: 'alert',\n ok: 'status',\n error: 'alert',\n info: 'status',\n};\n\nexport interface DriftToastProps {\n variant?: DriftToastVariant;\n title: ReactNode;\n description?: ReactNode;\n onClose?: () => void;\n closeLabel?: string;\n className?: string;\n}\n\n/**\n * DriftToast — Искра.DCI notification with a left status stripe, tuned for the\n * drift/sync/error/info lifecycle. Drift and error announce assertively\n * (`role=\"alert\"`); ok/info are polite (`role=\"status\"`).\n */\nexport function DriftToast({\n variant = 'info',\n title,\n description,\n onClose,\n closeLabel = 'Закрыть',\n className,\n}: DriftToastProps) {\n return (\n <div\n className={['dci-toast', `v-${variant}`, className].filter(Boolean).join(' ')}\n role={ROLE[variant]}\n >\n <span className=\"dci-toast-icon\" aria-hidden=\"true\">\n <Icon name={ICON[variant]} size={11} />\n </span>\n <div className=\"dci-toast-body\">\n <div className=\"dci-toast-title\">{title}</div>\n {description && <div className=\"dci-toast-desc\">{description}</div>}\n </div>\n {onClose && (\n <IconButton\n className=\"dci-toast-close\"\n variant=\"ghost\"\n size=\"s\"\n aria-label={closeLabel}\n onClick={onClose}\n icon={<Icon name=\"close\" size={13} />}\n />\n )}\n </div>\n );\n}\n","import { useMemo, useState } from 'react';\nimport { Button, Checkbox, Modal, TextField } from '@iskra-ui/react';\nimport './ApiKeyModal.css';\n\nexport interface ApiKeyScope {\n id: string;\n name: string;\n description?: string;\n}\n\nexport interface ApiKeyDraft {\n name: string;\n scopes: string[];\n}\n\nexport interface ApiKeyModalProps {\n open: boolean;\n onClose: () => void;\n /** Called with the validated draft when the user confirms creation. */\n onCreate: (draft: ApiKeyDraft) => void;\n scopes?: ApiKeyScope[];\n title?: string;\n submitLabel?: string;\n cancelLabel?: string;\n}\n\nconst DEFAULT_SCOPES: ApiKeyScope[] = [\n { id: 'devices:read', name: 'devices:read', description: 'Чтение состояния устройств' },\n { id: 'devices:write', name: 'devices:write', description: 'Применение конфигураций и sync' },\n { id: 'metrics:read', name: 'metrics:read', description: 'Доступ к метрикам и спарклайнам' },\n];\n\n/**\n * ApiKeyModal — domain dialog for minting a scoped API key. Built on the\n * foundation `Modal`, `TextField`, `Checkbox` and `Button`. Submit is disabled\n * until a name and at least one scope are provided.\n */\nexport function ApiKeyModal({\n open,\n onClose,\n onCreate,\n scopes = DEFAULT_SCOPES,\n title = 'Новый API-ключ',\n submitLabel = 'Создать ключ',\n cancelLabel = 'Отмена',\n}: ApiKeyModalProps) {\n const [name, setName] = useState('');\n const [selected, setSelected] = useState<Record<string, boolean>>({});\n\n const chosen = useMemo(\n () => scopes.filter((s) => selected[s.id]).map((s) => s.id),\n [scopes, selected],\n );\n const canSubmit = name.trim().length > 0 && chosen.length > 0;\n\n const reset = () => {\n setName('');\n setSelected({});\n };\n\n const handleClose = () => {\n reset();\n onClose();\n };\n\n const handleSubmit = () => {\n if (!canSubmit) return;\n onCreate({ name: name.trim(), scopes: chosen });\n reset();\n };\n\n return (\n <Modal\n open={open}\n onClose={handleClose}\n title={title}\n description=\"Ключ будет показан один раз после создания.\"\n size=\"m\"\n footer={\n <>\n <Button variant=\"ghost\" onClick={handleClose}>\n {cancelLabel}\n </Button>\n <Button variant=\"primary\" onClick={handleSubmit} disabled={!canSubmit}>\n {submitLabel}\n </Button>\n </>\n }\n >\n <div className=\"dci-apikey-form\">\n <TextField\n label=\"Название ключа\"\n placeholder=\"например, ci-deploy-bot\"\n required\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n <fieldset className=\"dci-apikey-scopes\">\n <legend className=\"dci-apikey-scopes-legend\">Права доступа</legend>\n {scopes.map((scope) => (\n <div className=\"dci-apikey-scope\" key={scope.id}>\n <Checkbox\n checked={Boolean(selected[scope.id])}\n onChange={(e) => setSelected((prev) => ({ ...prev, [scope.id]: e.target.checked }))}\n label={<span className=\"dci-apikey-scope-name\">{scope.name}</span>}\n description={scope.description}\n />\n </div>\n ))}\n </fieldset>\n </div>\n </Modal>\n );\n}\n"],"mappings":"sJAMA,IAAM,EAA6C,CACjD,KAAM,OACN,MAAO,QACP,MAAO,QACP,QAAS,SACX,EAyBA,SAAgB,EAAW,CACzB,OACA,KACA,SACA,cACA,cACA,cAAc,GACd,YAAY,CAAC,EACb,OAAO,CAAC,EACR,WACA,YACA,GAAG,GACe,CAClB,IAAM,EAAY,OAAO,GAAa,WAQtC,OACE,EAAA,EAAA,MAAC,EAAA,KAAD,CACE,QAAQ,IACR,YAAa,EACb,UAAW,CAAC,aAAc,GAAa,eAAgB,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAC1F,QAAS,EAAY,EAAW,IAAA,GAChC,UAAW,EAbI,GAAqC,CAClD,IAAc,EAAE,MAAQ,SAAW,EAAE,MAAQ,OAC/C,EAAE,eAAe,EACjB,EAAU,EAEd,EAQuC,IAAA,GACnC,KAAM,EAAY,SAAW,IAAA,GAC7B,aAAY,EAAY,GAAG,EAAK,KAAK,EAAa,KAAY,IAAA,GAC9D,GAAI,WARN,EAUE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,oBAAoB,IAAU,cAAY,MAAQ,CAAA,GACnE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,2BAAmB,CAAW,CAAA,GAC9C,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,uBAAuB,aAAW,EAAa,EAAc,CAAA,CAC3E,KACL,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,yBAAiB,CAAQ,CAAA,GACxC,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,6BAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,mCAA2B,CAAkB,CAAA,GAC7D,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,0BAA0B,EAAc,YAAc,cACpE,CACG,CAAA,CACH,IACJ,EAAU,OAAS,IAClB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,mBAAmB,cAAY,gBAC3C,EAAU,KAAK,EAAG,KACjB,EAAA,EAAA,KAAC,OAAD,CAEE,UAAW,iBAAiB,EAAc,YAAc,KACxD,MAAO,CAAE,OAAQ,GAAG,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAC,CAAC,EAAI,IAAI,EAAG,CAC1D,EAHM,CAGN,CACF,CACE,CAAA,EAEN,EAAK,OAAS,IACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,2BACZ,EAAK,IAAK,IACT,EAAA,EAAA,KAAC,OAAD,CAAc,UAAU,0BACrB,CACG,EAFK,CAEL,CACP,CACE,CAAA,CAEH,GAEV,CC5EA,IAAM,EAAS,GACT,EAAO,EAAI,KAAK,GAAK,EAO3B,SAAgB,EAAW,CACzB,UACA,SAAS,CAAC,EACV,QAAQ,gBACR,cAAc,GACd,OACA,eACA,aACkB,CAClB,IAAM,EAAa,GAAQ,KACrB,CAAC,EAAc,IAAA,EAAA,EAAA,UAA4B,CAAW,EACtD,EAAS,EAAa,EAAO,EAC7B,GAAA,EAAA,EAAA,OAAiB,EAEjB,EAAM,KAAK,IAAI,EAAG,KAAK,IAAI,IAAK,CAAO,CAAC,EACxC,EAAQ,EAAM,IAAO,EACrB,EAAY,EAAO,OAAS,EAQlC,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,CAAC,kBAAmB,GAAU,UAAW,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,WAA5F,EACE,EAAA,EAAA,MAAC,SAAD,CACE,KAAK,SACL,UAAU,iBACV,YAXe,CACnB,IAAM,EAAO,CAAC,EACT,GAAY,EAAgB,CAAI,EACrC,IAAe,CAAI,CACrB,EAQM,gBAAe,EACf,gBAAe,EAAY,EAAW,IAAA,YALxC,EAOE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,iBAAiB,QAAQ,YAAY,cAAY,gBAAhE,EACE,EAAA,EAAA,KAAC,SAAD,CACE,GAAG,KACH,GAAG,KACH,EAAG,EACH,KAAK,OACL,OAAO,uBACP,YAAY,GACb,CAAA,GACD,EAAA,EAAA,KAAC,SAAD,CACE,GAAG,KACH,GAAG,KACH,EAAG,EACH,KAAK,OACL,OAAO,yBACP,YAAY,IACZ,gBAAiB,GAAG,EAAK,GAAG,EAAO,IACnC,cAAc,QACd,UAAU,mBACX,CAAA,CACE,KACL,EAAA,EAAA,MAAC,OAAD,CAAA,SAAA,EACE,EAAA,EAAA,MAAC,OAAD,CAAM,UAAU,yBAAhB,CAAiC,EAAI,GAAO,KAC5C,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,2BAAmB,CAAY,CAAA,EAC9C,IACC,EAAA,EAAA,MAAC,OAAD,CAAM,UAAU,yBAAhB,EACE,EAAA,EAAA,KAAC,IAAD,CAAA,SAAI,EAAO,MAAU,CAAA,EAAC,yDAClB,GAEJ,CAAA,CAAA,GACN,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,iBAAiB,cAAY,iBAC3C,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAK,eAAe,KAAM,EAAK,CAAA,CACjC,CAAA,CACA,IACP,GAAa,IACZ,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mBAAmB,GAAI,WAAtC,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,+BAAf,CAAqC,2BAAyB,EAAO,MAAY,IAChF,EAAO,IAAK,IACX,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,yBAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,yBAAyB,EAAM,WAAY,cAAY,MAAQ,CAAA,GAChF,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,8BAAsB,EAAM,IAAW,CAAA,GACvD,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,gCAAwB,EAAM,MAAa,CAAA,GAC3D,EAAA,EAAA,KAAC,EAAA,MAAD,CAAO,QAAS,EAAM,WAAa,QAAU,QAAU,UAAW,KAAK,aACpE,EAAM,WAAa,QAAU,QAAU,OACnC,CAAA,EACN,EAAM,cACL,EAAA,EAAA,KAAC,EAAA,OAAD,CACE,QAAQ,UACR,KAAK,IACL,QAAS,EAAM,SACf,YAAY,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAK,OAAO,KAAM,EAAK,CAAA,WAExC,EAAM,WACD,CAAA,CAEP,GAjB+B,EAAM,EAiBrC,CACN,CACE,GAEJ,GAET,CC9GA,SAAgB,EAAO,CACrB,UACA,SACA,YAAY,OACZ,cAAc,SACd,aACc,CACd,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,UAAsB,EAAK,EAY1C,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,CAAC,UAAW,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,WAA/D,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,eAAe,cAAY,gBAAO,KAE5C,CAAA,GACN,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,wBAAgB,CAAc,CAAA,GAC9C,EAAA,EAAA,KAAC,EAAA,OAAD,CACE,QAAQ,UACR,KAAK,IACL,YAnBmB,CACnB,EACF,EAAO,CAAO,EACL,OAAO,UAAc,KAAe,UAAU,WACvD,UAAe,UAAU,UAAU,CAAO,EAE5C,EAAU,EAAI,EACd,eAAiB,EAAU,EAAK,EAAG,IAAI,CACzC,EAYM,YAAY,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAM,EAAS,QAAU,OAAQ,KAAM,EAAK,CAAA,WAE7D,EAAS,EAAc,CAClB,CAAA,CACL,GAET,CC/CA,IAAM,EAA4C,CAChD,MAAO,UACP,GAAI,eACJ,MAAO,WACP,KAAM,MACR,EAEM,EAAsD,CAC1D,MAAO,QACP,GAAI,SACJ,MAAO,QACP,KAAM,QACR,EAgBA,SAAgB,EAAW,CACzB,UAAU,OACV,QACA,cACA,UACA,aAAa,UACb,aACkB,CAClB,OACE,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,CAAC,YAAa,KAAK,IAAW,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAC5E,KAAM,EAAK,YAFb,EAIE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,iBAAiB,cAAY,iBAC3C,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAM,EAAK,GAAU,KAAM,EAAK,CAAA,CAClC,CAAA,GACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,2BAAmB,CAAW,CAAA,EAC5C,IAAe,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,0BAAkB,CAAiB,CAAA,CAC/D,IACJ,IACC,EAAA,EAAA,KAAC,EAAA,WAAD,CACE,UAAU,kBACV,QAAQ,QACR,KAAK,IACL,aAAY,EACZ,QAAS,EACT,MAAM,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,KAAK,QAAQ,KAAM,EAAK,CAAA,CACrC,CAAA,CAEA,GAET,CCxCA,IAAM,EAAgC,CACpC,CAAE,GAAI,eAAgB,KAAM,eAAgB,YAAa,4BAA6B,EACtF,CAAE,GAAI,gBAAiB,KAAM,gBAAiB,YAAa,gCAAiC,EAC5F,CAAE,GAAI,eAAgB,KAAM,eAAgB,YAAa,iCAAkC,CAC7F,EAOA,SAAgB,EAAY,CAC1B,OACA,UACA,WACA,SAAS,EACT,QAAQ,iBACR,cAAc,eACd,cAAc,UACK,CACnB,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,UAAoB,EAAE,EAC7B,CAAC,EAAU,IAAA,EAAA,EAAA,UAAiD,CAAC,CAAC,EAE9D,GAAA,EAAA,EAAA,aACE,EAAO,OAAQ,GAAM,EAAS,EAAE,GAAG,EAAE,IAAK,GAAM,EAAE,EAAE,EAC1D,CAAC,EAAQ,CAAQ,CACnB,EACM,EAAY,EAAK,KAAK,EAAE,OAAS,GAAK,EAAO,OAAS,EAEtD,MAAc,CAClB,EAAQ,EAAE,EACV,EAAY,CAAC,CAAC,CAChB,EAEM,MAAoB,CACxB,EAAM,EACN,EAAQ,CACV,EAQA,OACE,EAAA,EAAA,KAAC,EAAA,MAAD,CACQ,OACN,QAAS,EACF,QACP,YAAY,8CACZ,KAAK,IACL,QACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,QAAQ,QAAS,WAC9B,CACK,CAAA,GACR,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,QAAQ,UAAU,YAlBP,CACpB,IACL,EAAS,CAAE,KAAM,EAAK,KAAK,EAAG,OAAQ,CAAO,CAAC,EAC9C,EAAM,EACR,EAcyD,SAAU,CAAC,WACzD,CACK,CAAA,CACR,CAAA,CAAA,YAGJ,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,2BAAf,EACE,EAAA,EAAA,KAAC,EAAA,UAAD,CACE,MAAM,iBACN,YAAY,0BACZ,SAAA,GACA,MAAO,EACP,SAAW,GAAM,EAAQ,EAAE,OAAO,KAAK,CACxC,CAAA,GACD,EAAA,EAAA,MAAC,WAAD,CAAU,UAAU,6BAApB,EACE,EAAA,EAAA,KAAC,SAAD,CAAQ,UAAU,oCAA2B,eAAqB,CAAA,EACjE,EAAO,IAAK,IACX,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,6BACb,EAAA,EAAA,KAAC,EAAA,SAAD,CACE,QAAS,EAAQ,EAAS,EAAM,IAChC,SAAW,GAAM,EAAa,IAAU,CAAE,GAAG,GAAO,EAAM,IAAK,EAAE,OAAO,OAAQ,EAAE,EAClF,OAAO,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,iCAAyB,EAAM,IAAW,CAAA,EACjE,YAAa,EAAM,WACpB,CAAA,CACE,EAPkC,EAAM,EAOxC,CACN,CACO,GACP,GACA,CAAA,CAEX"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { DeviceCard, type DeviceCardProps, type DeviceStatus, } from './components/DeviceCard/DeviceCard.js';
|
|
2
|
+
export { FleetPulse, type FleetPulseProps, type FleetIssue, type IssueSeverity, } from './components/FleetPulse/FleetPulse.js';
|
|
3
|
+
export { CliRow, type CliRowProps } from './components/CliRow/CliRow.js';
|
|
4
|
+
export { DriftToast, type DriftToastProps, type DriftToastVariant, } from './components/DriftToast/DriftToast.js';
|
|
5
|
+
export { ApiKeyModal, type ApiKeyModalProps, type ApiKeyScope, type ApiKeyDraft, } from './components/ApiKeyModal/ApiKeyModal.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,aAAa,GACnB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,WAAW,EACX,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,yCAAyC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { useId as e, useMemo as t, useState as n } from "react";
|
|
2
|
+
import { Badge as r, Button as i, Card as a, Checkbox as o, Icon as s, IconButton as c, Modal as l, TextField as u } from "@iskra-ui/react";
|
|
3
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/DeviceCard/DeviceCard.tsx
|
|
5
|
+
var m = {
|
|
6
|
+
sync: "Sync",
|
|
7
|
+
drift: "Drift",
|
|
8
|
+
error: "Error",
|
|
9
|
+
offline: "Offline"
|
|
10
|
+
};
|
|
11
|
+
function h({ name: e, ip: t, status: n, metricLabel: r, metricValue: i, metricAlert: o = !1, sparkline: s = [], tags: c = [], onSelect: l, className: u, ...d }) {
|
|
12
|
+
let h = typeof l == "function";
|
|
13
|
+
return /* @__PURE__ */ p(a, {
|
|
14
|
+
padding: "s",
|
|
15
|
+
interactive: h,
|
|
16
|
+
className: [
|
|
17
|
+
"dci-device",
|
|
18
|
+
h && "is-clickable",
|
|
19
|
+
u
|
|
20
|
+
].filter(Boolean).join(" "),
|
|
21
|
+
onClick: h ? l : void 0,
|
|
22
|
+
onKeyDown: h ? (e) => {
|
|
23
|
+
h && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), l());
|
|
24
|
+
} : void 0,
|
|
25
|
+
role: h ? "button" : void 0,
|
|
26
|
+
"aria-label": h ? `${e} — ${m[n]}` : void 0,
|
|
27
|
+
...d,
|
|
28
|
+
children: [
|
|
29
|
+
/* @__PURE__ */ p("div", {
|
|
30
|
+
className: "dci-device-top",
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ f("span", {
|
|
33
|
+
className: `dci-device-dot s-${n}`,
|
|
34
|
+
"aria-hidden": "true"
|
|
35
|
+
}),
|
|
36
|
+
/* @__PURE__ */ f("span", {
|
|
37
|
+
className: "dci-device-name",
|
|
38
|
+
children: e
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ f("span", {
|
|
41
|
+
className: `dci-device-status s-${n}`,
|
|
42
|
+
children: m[n]
|
|
43
|
+
})
|
|
44
|
+
]
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ f("div", {
|
|
47
|
+
className: "dci-device-ip",
|
|
48
|
+
children: t
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ p("div", {
|
|
51
|
+
className: "dci-device-metahd",
|
|
52
|
+
children: [/* @__PURE__ */ f("span", {
|
|
53
|
+
className: "dci-device-metric-label",
|
|
54
|
+
children: r
|
|
55
|
+
}), /* @__PURE__ */ f("span", {
|
|
56
|
+
className: `dci-device-metric-value${o ? " is-alert" : ""}`,
|
|
57
|
+
children: i
|
|
58
|
+
})]
|
|
59
|
+
}),
|
|
60
|
+
s.length > 0 && /* @__PURE__ */ f("div", {
|
|
61
|
+
className: "dci-device-spark",
|
|
62
|
+
"aria-hidden": "true",
|
|
63
|
+
children: s.map((e, t) => /* @__PURE__ */ f("span", {
|
|
64
|
+
className: `dci-device-bar${o ? " is-alert" : ""}`,
|
|
65
|
+
style: { height: `${Math.max(0, Math.min(1, e)) * 100}%` }
|
|
66
|
+
}, t))
|
|
67
|
+
}),
|
|
68
|
+
c.length > 0 && /* @__PURE__ */ f("div", {
|
|
69
|
+
className: "dci-device-tags",
|
|
70
|
+
children: c.map((e) => /* @__PURE__ */ f("span", {
|
|
71
|
+
className: "dci-device-tag",
|
|
72
|
+
children: e
|
|
73
|
+
}, e))
|
|
74
|
+
})
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/components/FleetPulse/FleetPulse.tsx
|
|
80
|
+
var g = 22, _ = 2 * Math.PI * g;
|
|
81
|
+
function v({ percent: t, issues: a = [], label: o = "Fleet in Sync", defaultOpen: c = !1, open: l, onOpenChange: u, className: d }) {
|
|
82
|
+
let m = l != null, [h, v] = n(c), y = m ? l : h, b = e(), x = Math.max(0, Math.min(100, t)), S = x / 100 * _, C = a.length > 0;
|
|
83
|
+
return /* @__PURE__ */ p("div", {
|
|
84
|
+
className: [
|
|
85
|
+
"dci-pulse-panel",
|
|
86
|
+
y && "is-open",
|
|
87
|
+
d
|
|
88
|
+
].filter(Boolean).join(" "),
|
|
89
|
+
children: [/* @__PURE__ */ p("button", {
|
|
90
|
+
type: "button",
|
|
91
|
+
className: "dci-pulse-head",
|
|
92
|
+
onClick: () => {
|
|
93
|
+
let e = !y;
|
|
94
|
+
m || v(e), u?.(e);
|
|
95
|
+
},
|
|
96
|
+
"aria-expanded": y,
|
|
97
|
+
"aria-controls": C ? b : void 0,
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ p("svg", {
|
|
100
|
+
className: "dci-pulse-ring",
|
|
101
|
+
viewBox: "0 0 56 56",
|
|
102
|
+
"aria-hidden": "true",
|
|
103
|
+
children: [/* @__PURE__ */ f("circle", {
|
|
104
|
+
cx: "28",
|
|
105
|
+
cy: "28",
|
|
106
|
+
r: g,
|
|
107
|
+
fill: "none",
|
|
108
|
+
stroke: "var(--line, #30363d)",
|
|
109
|
+
strokeWidth: "4"
|
|
110
|
+
}), /* @__PURE__ */ f("circle", {
|
|
111
|
+
cx: "28",
|
|
112
|
+
cy: "28",
|
|
113
|
+
r: g,
|
|
114
|
+
fill: "none",
|
|
115
|
+
stroke: "var(--accent, #00ffc2)",
|
|
116
|
+
strokeWidth: "4",
|
|
117
|
+
strokeDasharray: `${S} ${_ - S}`,
|
|
118
|
+
strokeLinecap: "round",
|
|
119
|
+
transform: "rotate(-90 28 28)"
|
|
120
|
+
})]
|
|
121
|
+
}),
|
|
122
|
+
/* @__PURE__ */ p("span", { children: [
|
|
123
|
+
/* @__PURE__ */ p("span", {
|
|
124
|
+
className: "dci-pulse-pct",
|
|
125
|
+
children: [x, "%"]
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ f("span", {
|
|
128
|
+
className: "dci-pulse-label",
|
|
129
|
+
children: o
|
|
130
|
+
}),
|
|
131
|
+
C && /* @__PURE__ */ p("span", {
|
|
132
|
+
className: "dci-pulse-sub",
|
|
133
|
+
children: [/* @__PURE__ */ f("b", { children: a.length }), " устройств требуют внимания — нажмите, чтобы развернуть"]
|
|
134
|
+
})
|
|
135
|
+
] }),
|
|
136
|
+
/* @__PURE__ */ f("span", {
|
|
137
|
+
className: "dci-pulse-chev",
|
|
138
|
+
"aria-hidden": "true",
|
|
139
|
+
children: /* @__PURE__ */ f(s, {
|
|
140
|
+
name: "chevron-down",
|
|
141
|
+
size: 16
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
]
|
|
145
|
+
}), C && y && /* @__PURE__ */ p("div", {
|
|
146
|
+
className: "dci-pulse-issues",
|
|
147
|
+
id: b,
|
|
148
|
+
children: [/* @__PURE__ */ p("div", {
|
|
149
|
+
className: "dci-pulse-issues-hd",
|
|
150
|
+
children: ["Проблемные устройства · ", a.length]
|
|
151
|
+
}), a.map((e) => /* @__PURE__ */ p("div", {
|
|
152
|
+
className: "dci-pulse-row",
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ f("span", {
|
|
155
|
+
className: `dci-pulse-row-dot sev-${e.severity}`,
|
|
156
|
+
"aria-hidden": "true"
|
|
157
|
+
}),
|
|
158
|
+
/* @__PURE__ */ f("span", {
|
|
159
|
+
className: "dci-pulse-row-name",
|
|
160
|
+
children: e.name
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ f("span", {
|
|
163
|
+
className: "dci-pulse-row-reason",
|
|
164
|
+
children: e.reason
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ f(r, {
|
|
167
|
+
variant: e.severity === "error" ? "error" : "warning",
|
|
168
|
+
size: "s",
|
|
169
|
+
children: e.severity === "error" ? "Error" : "Drift"
|
|
170
|
+
}),
|
|
171
|
+
e.actionLabel && /* @__PURE__ */ f(i, {
|
|
172
|
+
variant: "outline",
|
|
173
|
+
size: "s",
|
|
174
|
+
onClick: e.onAction,
|
|
175
|
+
iconBefore: /* @__PURE__ */ f(s, {
|
|
176
|
+
name: "sync",
|
|
177
|
+
size: 13
|
|
178
|
+
}),
|
|
179
|
+
children: e.actionLabel
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
}, e.id))]
|
|
183
|
+
})]
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/components/CliRow/CliRow.tsx
|
|
188
|
+
function y({ command: e, onCopy: t, copyLabel: r = "Copy", copiedLabel: a = "Copied", className: o }) {
|
|
189
|
+
let [c, l] = n(!1);
|
|
190
|
+
return /* @__PURE__ */ p("div", {
|
|
191
|
+
className: ["dci-cli", o].filter(Boolean).join(" "),
|
|
192
|
+
children: [
|
|
193
|
+
/* @__PURE__ */ f("span", {
|
|
194
|
+
className: "dci-cli-icon",
|
|
195
|
+
"aria-hidden": "true",
|
|
196
|
+
children: "</>"
|
|
197
|
+
}),
|
|
198
|
+
/* @__PURE__ */ f("code", {
|
|
199
|
+
className: "dci-cli-text",
|
|
200
|
+
children: e
|
|
201
|
+
}),
|
|
202
|
+
/* @__PURE__ */ f(i, {
|
|
203
|
+
variant: "outline",
|
|
204
|
+
size: "s",
|
|
205
|
+
onClick: () => {
|
|
206
|
+
t ? t(e) : typeof navigator < "u" && navigator.clipboard && navigator.clipboard.writeText(e), l(!0), setTimeout(() => l(!1), 1500);
|
|
207
|
+
},
|
|
208
|
+
iconBefore: /* @__PURE__ */ f(s, {
|
|
209
|
+
name: c ? "check" : "copy",
|
|
210
|
+
size: 13
|
|
211
|
+
}),
|
|
212
|
+
children: c ? a : r
|
|
213
|
+
})
|
|
214
|
+
]
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/components/DriftToast/DriftToast.tsx
|
|
219
|
+
var b = {
|
|
220
|
+
drift: "warning",
|
|
221
|
+
ok: "check-circle",
|
|
222
|
+
error: "x-circle",
|
|
223
|
+
info: "info"
|
|
224
|
+
}, x = {
|
|
225
|
+
drift: "alert",
|
|
226
|
+
ok: "status",
|
|
227
|
+
error: "alert",
|
|
228
|
+
info: "status"
|
|
229
|
+
};
|
|
230
|
+
function S({ variant: e = "info", title: t, description: n, onClose: r, closeLabel: i = "Закрыть", className: a }) {
|
|
231
|
+
return /* @__PURE__ */ p("div", {
|
|
232
|
+
className: [
|
|
233
|
+
"dci-toast",
|
|
234
|
+
`v-${e}`,
|
|
235
|
+
a
|
|
236
|
+
].filter(Boolean).join(" "),
|
|
237
|
+
role: x[e],
|
|
238
|
+
children: [
|
|
239
|
+
/* @__PURE__ */ f("span", {
|
|
240
|
+
className: "dci-toast-icon",
|
|
241
|
+
"aria-hidden": "true",
|
|
242
|
+
children: /* @__PURE__ */ f(s, {
|
|
243
|
+
name: b[e],
|
|
244
|
+
size: 11
|
|
245
|
+
})
|
|
246
|
+
}),
|
|
247
|
+
/* @__PURE__ */ p("div", {
|
|
248
|
+
className: "dci-toast-body",
|
|
249
|
+
children: [/* @__PURE__ */ f("div", {
|
|
250
|
+
className: "dci-toast-title",
|
|
251
|
+
children: t
|
|
252
|
+
}), n && /* @__PURE__ */ f("div", {
|
|
253
|
+
className: "dci-toast-desc",
|
|
254
|
+
children: n
|
|
255
|
+
})]
|
|
256
|
+
}),
|
|
257
|
+
r && /* @__PURE__ */ f(c, {
|
|
258
|
+
className: "dci-toast-close",
|
|
259
|
+
variant: "ghost",
|
|
260
|
+
size: "s",
|
|
261
|
+
"aria-label": i,
|
|
262
|
+
onClick: r,
|
|
263
|
+
icon: /* @__PURE__ */ f(s, {
|
|
264
|
+
name: "close",
|
|
265
|
+
size: 13
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
]
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/components/ApiKeyModal/ApiKeyModal.tsx
|
|
273
|
+
var C = [
|
|
274
|
+
{
|
|
275
|
+
id: "devices:read",
|
|
276
|
+
name: "devices:read",
|
|
277
|
+
description: "Чтение состояния устройств"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: "devices:write",
|
|
281
|
+
name: "devices:write",
|
|
282
|
+
description: "Применение конфигураций и sync"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "metrics:read",
|
|
286
|
+
name: "metrics:read",
|
|
287
|
+
description: "Доступ к метрикам и спарклайнам"
|
|
288
|
+
}
|
|
289
|
+
];
|
|
290
|
+
function w({ open: e, onClose: r, onCreate: a, scopes: s = C, title: c = "Новый API-ключ", submitLabel: m = "Создать ключ", cancelLabel: h = "Отмена" }) {
|
|
291
|
+
let [g, _] = n(""), [v, y] = n({}), b = t(() => s.filter((e) => v[e.id]).map((e) => e.id), [s, v]), x = g.trim().length > 0 && b.length > 0, S = () => {
|
|
292
|
+
_(""), y({});
|
|
293
|
+
}, w = () => {
|
|
294
|
+
S(), r();
|
|
295
|
+
};
|
|
296
|
+
return /* @__PURE__ */ f(l, {
|
|
297
|
+
open: e,
|
|
298
|
+
onClose: w,
|
|
299
|
+
title: c,
|
|
300
|
+
description: "Ключ будет показан один раз после создания.",
|
|
301
|
+
size: "m",
|
|
302
|
+
footer: /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(i, {
|
|
303
|
+
variant: "ghost",
|
|
304
|
+
onClick: w,
|
|
305
|
+
children: h
|
|
306
|
+
}), /* @__PURE__ */ f(i, {
|
|
307
|
+
variant: "primary",
|
|
308
|
+
onClick: () => {
|
|
309
|
+
x && (a({
|
|
310
|
+
name: g.trim(),
|
|
311
|
+
scopes: b
|
|
312
|
+
}), S());
|
|
313
|
+
},
|
|
314
|
+
disabled: !x,
|
|
315
|
+
children: m
|
|
316
|
+
})] }),
|
|
317
|
+
children: /* @__PURE__ */ p("div", {
|
|
318
|
+
className: "dci-apikey-form",
|
|
319
|
+
children: [/* @__PURE__ */ f(u, {
|
|
320
|
+
label: "Название ключа",
|
|
321
|
+
placeholder: "например, ci-deploy-bot",
|
|
322
|
+
required: !0,
|
|
323
|
+
value: g,
|
|
324
|
+
onChange: (e) => _(e.target.value)
|
|
325
|
+
}), /* @__PURE__ */ p("fieldset", {
|
|
326
|
+
className: "dci-apikey-scopes",
|
|
327
|
+
children: [/* @__PURE__ */ f("legend", {
|
|
328
|
+
className: "dci-apikey-scopes-legend",
|
|
329
|
+
children: "Права доступа"
|
|
330
|
+
}), s.map((e) => /* @__PURE__ */ f("div", {
|
|
331
|
+
className: "dci-apikey-scope",
|
|
332
|
+
children: /* @__PURE__ */ f(o, {
|
|
333
|
+
checked: !!v[e.id],
|
|
334
|
+
onChange: (t) => y((n) => ({
|
|
335
|
+
...n,
|
|
336
|
+
[e.id]: t.target.checked
|
|
337
|
+
})),
|
|
338
|
+
label: /* @__PURE__ */ f("span", {
|
|
339
|
+
className: "dci-apikey-scope-name",
|
|
340
|
+
children: e.name
|
|
341
|
+
}),
|
|
342
|
+
description: e.description
|
|
343
|
+
})
|
|
344
|
+
}, e.id))]
|
|
345
|
+
})]
|
|
346
|
+
})
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
//#endregion
|
|
350
|
+
export { w as ApiKeyModal, y as CliRow, h as DeviceCard, S as DriftToast, v as FleetPulse };
|
|
351
|
+
|
|
352
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/components/DeviceCard/DeviceCard.tsx","../src/components/FleetPulse/FleetPulse.tsx","../src/components/CliRow/CliRow.tsx","../src/components/DriftToast/DriftToast.tsx","../src/components/ApiKeyModal/ApiKeyModal.tsx"],"sourcesContent":["import { type KeyboardEvent } from 'react';\nimport { Card, type CardProps } from '@iskra-ui/react';\nimport './DeviceCard.css';\n\nexport type DeviceStatus = 'sync' | 'drift' | 'error' | 'offline';\n\nconst STATUS_LABEL: Record<DeviceStatus, string> = {\n sync: 'Sync',\n drift: 'Drift',\n error: 'Error',\n offline: 'Offline',\n};\n\nexport interface DeviceCardProps extends Omit<CardProps, 'children' | 'title'> {\n /** Device hostname, e.g. `spine-01.msk`. */\n name: string;\n /** Management IP. */\n ip: string;\n status: DeviceStatus;\n /** Sparkline metric label, e.g. `CPU · 24 ч`. */\n metricLabel: string;\n /** Formatted metric value, e.g. `88%`. */\n metricValue: string;\n /** Render the metric value + bars in the alert (warn) colour. */\n metricAlert?: boolean;\n /** Normalised sparkline samples in the 0..1 range. */\n sparkline?: number[];\n tags?: string[];\n onSelect?: () => void;\n}\n\n/**\n * DeviceCard — fleet device tile with status, a single configurable sparkline\n * metric and tags. Built on the foundation `Card`. Set `onSelect` to make it an\n * accessible button-like surface.\n */\nexport function DeviceCard({\n name,\n ip,\n status,\n metricLabel,\n metricValue,\n metricAlert = false,\n sparkline = [],\n tags = [],\n onSelect,\n className,\n ...rest\n}: DeviceCardProps) {\n const clickable = typeof onSelect === 'function';\n const onKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (clickable && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n onSelect!();\n }\n };\n\n return (\n <Card\n padding=\"s\"\n interactive={clickable}\n className={['dci-device', clickable && 'is-clickable', className].filter(Boolean).join(' ')}\n onClick={clickable ? onSelect : undefined}\n onKeyDown={clickable ? onKeyDown : undefined}\n role={clickable ? 'button' : undefined}\n aria-label={clickable ? `${name} — ${STATUS_LABEL[status]}` : undefined}\n {...rest}\n >\n <div className=\"dci-device-top\">\n <span className={`dci-device-dot s-${status}`} aria-hidden=\"true\" />\n <span className=\"dci-device-name\">{name}</span>\n <span className={`dci-device-status s-${status}`}>{STATUS_LABEL[status]}</span>\n </div>\n <div className=\"dci-device-ip\">{ip}</div>\n <div className=\"dci-device-metahd\">\n <span className=\"dci-device-metric-label\">{metricLabel}</span>\n <span className={`dci-device-metric-value${metricAlert ? ' is-alert' : ''}`}>\n {metricValue}\n </span>\n </div>\n {sparkline.length > 0 && (\n <div className=\"dci-device-spark\" aria-hidden=\"true\">\n {sparkline.map((v, i) => (\n <span\n key={i}\n className={`dci-device-bar${metricAlert ? ' is-alert' : ''}`}\n style={{ height: `${Math.max(0, Math.min(1, v)) * 100}%` }}\n />\n ))}\n </div>\n )}\n {tags.length > 0 && (\n <div className=\"dci-device-tags\">\n {tags.map((t) => (\n <span key={t} className=\"dci-device-tag\">\n {t}\n </span>\n ))}\n </div>\n )}\n </Card>\n );\n}\n","import { useId, useState } from 'react';\nimport { Badge, Button, Icon } from '@iskra-ui/react';\nimport './FleetPulse.css';\n\nexport type IssueSeverity = 'error' | 'drift';\n\nexport interface FleetIssue {\n id: string;\n name: string;\n reason: string;\n severity: IssueSeverity;\n actionLabel?: string;\n onAction?: () => void;\n}\n\nexport interface FleetPulseProps {\n /** Percentage of the fleet in sync (0–100). */\n percent: number;\n issues?: FleetIssue[];\n label?: string;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n className?: string;\n}\n\nconst RADIUS = 22;\nconst CIRC = 2 * Math.PI * RADIUS;\n\n/**\n * FleetPulse — interactive sync ring summarising fleet health that expands into\n * a list of problem devices with inline remediation actions. Controlled or\n * uncontrolled via `open`/`defaultOpen`.\n */\nexport function FleetPulse({\n percent,\n issues = [],\n label = 'Fleet in Sync',\n defaultOpen = false,\n open,\n onOpenChange,\n className,\n}: FleetPulseProps) {\n const controlled = open != null;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isOpen = controlled ? open : internalOpen;\n const issuesId = useId();\n\n const pct = Math.max(0, Math.min(100, percent));\n const dash = (pct / 100) * CIRC;\n const hasIssues = issues.length > 0;\n\n const toggle = () => {\n const next = !isOpen;\n if (!controlled) setInternalOpen(next);\n onOpenChange?.(next);\n };\n\n return (\n <div className={['dci-pulse-panel', isOpen && 'is-open', className].filter(Boolean).join(' ')}>\n <button\n type=\"button\"\n className=\"dci-pulse-head\"\n onClick={toggle}\n aria-expanded={isOpen}\n aria-controls={hasIssues ? issuesId : undefined}\n >\n <svg className=\"dci-pulse-ring\" viewBox=\"0 0 56 56\" aria-hidden=\"true\">\n <circle\n cx=\"28\"\n cy=\"28\"\n r={RADIUS}\n fill=\"none\"\n stroke=\"var(--line, #30363d)\"\n strokeWidth=\"4\"\n />\n <circle\n cx=\"28\"\n cy=\"28\"\n r={RADIUS}\n fill=\"none\"\n stroke=\"var(--accent, #00ffc2)\"\n strokeWidth=\"4\"\n strokeDasharray={`${dash} ${CIRC - dash}`}\n strokeLinecap=\"round\"\n transform=\"rotate(-90 28 28)\"\n />\n </svg>\n <span>\n <span className=\"dci-pulse-pct\">{pct}%</span>\n <span className=\"dci-pulse-label\">{label}</span>\n {hasIssues && (\n <span className=\"dci-pulse-sub\">\n <b>{issues.length}</b> устройств требуют внимания — нажмите, чтобы развернуть\n </span>\n )}\n </span>\n <span className=\"dci-pulse-chev\" aria-hidden=\"true\">\n <Icon name=\"chevron-down\" size={16} />\n </span>\n </button>\n {hasIssues && isOpen && (\n <div className=\"dci-pulse-issues\" id={issuesId}>\n <div className=\"dci-pulse-issues-hd\">Проблемные устройства · {issues.length}</div>\n {issues.map((issue) => (\n <div className=\"dci-pulse-row\" key={issue.id}>\n <span className={`dci-pulse-row-dot sev-${issue.severity}`} aria-hidden=\"true\" />\n <span className=\"dci-pulse-row-name\">{issue.name}</span>\n <span className=\"dci-pulse-row-reason\">{issue.reason}</span>\n <Badge variant={issue.severity === 'error' ? 'error' : 'warning'} size=\"s\">\n {issue.severity === 'error' ? 'Error' : 'Drift'}\n </Badge>\n {issue.actionLabel && (\n <Button\n variant=\"outline\"\n size=\"s\"\n onClick={issue.onAction}\n iconBefore={<Icon name=\"sync\" size={13} />}\n >\n {issue.actionLabel}\n </Button>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { Button, Icon } from '@iskra-ui/react';\nimport './CliRow.css';\n\nexport interface CliRowProps {\n /** The command string to display and copy. */\n command: string;\n /** Custom copy handler. Defaults to the Clipboard API. */\n onCopy?: (command: string) => void;\n copyLabel?: string;\n copiedLabel?: string;\n className?: string;\n}\n\n/**\n * CliRow — monospace command row with a copy-to-clipboard affordance. Used to\n * surface the equivalent API/CLI call for an action performed in the UI.\n */\nexport function CliRow({\n command,\n onCopy,\n copyLabel = 'Copy',\n copiedLabel = 'Copied',\n className,\n}: CliRowProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = () => {\n if (onCopy) {\n onCopy(command);\n } else if (typeof navigator !== 'undefined' && navigator.clipboard) {\n void navigator.clipboard.writeText(command);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n\n return (\n <div className={['dci-cli', className].filter(Boolean).join(' ')}>\n <span className=\"dci-cli-icon\" aria-hidden=\"true\">\n </>\n </span>\n <code className=\"dci-cli-text\">{command}</code>\n <Button\n variant=\"outline\"\n size=\"s\"\n onClick={handleCopy}\n iconBefore={<Icon name={copied ? 'check' : 'copy'} size={13} />}\n >\n {copied ? copiedLabel : copyLabel}\n </Button>\n </div>\n );\n}\n","import { type ReactNode } from 'react';\nimport { IconButton, Icon, type IconName } from '@iskra-ui/react';\nimport './DriftToast.css';\n\nexport type DriftToastVariant = 'drift' | 'ok' | 'error' | 'info';\n\nconst ICON: Record<DriftToastVariant, IconName> = {\n drift: 'warning',\n ok: 'check-circle',\n error: 'x-circle',\n info: 'info',\n};\n\nconst ROLE: Record<DriftToastVariant, 'alert' | 'status'> = {\n drift: 'alert',\n ok: 'status',\n error: 'alert',\n info: 'status',\n};\n\nexport interface DriftToastProps {\n variant?: DriftToastVariant;\n title: ReactNode;\n description?: ReactNode;\n onClose?: () => void;\n closeLabel?: string;\n className?: string;\n}\n\n/**\n * DriftToast — Искра.DCI notification with a left status stripe, tuned for the\n * drift/sync/error/info lifecycle. Drift and error announce assertively\n * (`role=\"alert\"`); ok/info are polite (`role=\"status\"`).\n */\nexport function DriftToast({\n variant = 'info',\n title,\n description,\n onClose,\n closeLabel = 'Закрыть',\n className,\n}: DriftToastProps) {\n return (\n <div\n className={['dci-toast', `v-${variant}`, className].filter(Boolean).join(' ')}\n role={ROLE[variant]}\n >\n <span className=\"dci-toast-icon\" aria-hidden=\"true\">\n <Icon name={ICON[variant]} size={11} />\n </span>\n <div className=\"dci-toast-body\">\n <div className=\"dci-toast-title\">{title}</div>\n {description && <div className=\"dci-toast-desc\">{description}</div>}\n </div>\n {onClose && (\n <IconButton\n className=\"dci-toast-close\"\n variant=\"ghost\"\n size=\"s\"\n aria-label={closeLabel}\n onClick={onClose}\n icon={<Icon name=\"close\" size={13} />}\n />\n )}\n </div>\n );\n}\n","import { useMemo, useState } from 'react';\nimport { Button, Checkbox, Modal, TextField } from '@iskra-ui/react';\nimport './ApiKeyModal.css';\n\nexport interface ApiKeyScope {\n id: string;\n name: string;\n description?: string;\n}\n\nexport interface ApiKeyDraft {\n name: string;\n scopes: string[];\n}\n\nexport interface ApiKeyModalProps {\n open: boolean;\n onClose: () => void;\n /** Called with the validated draft when the user confirms creation. */\n onCreate: (draft: ApiKeyDraft) => void;\n scopes?: ApiKeyScope[];\n title?: string;\n submitLabel?: string;\n cancelLabel?: string;\n}\n\nconst DEFAULT_SCOPES: ApiKeyScope[] = [\n { id: 'devices:read', name: 'devices:read', description: 'Чтение состояния устройств' },\n { id: 'devices:write', name: 'devices:write', description: 'Применение конфигураций и sync' },\n { id: 'metrics:read', name: 'metrics:read', description: 'Доступ к метрикам и спарклайнам' },\n];\n\n/**\n * ApiKeyModal — domain dialog for minting a scoped API key. Built on the\n * foundation `Modal`, `TextField`, `Checkbox` and `Button`. Submit is disabled\n * until a name and at least one scope are provided.\n */\nexport function ApiKeyModal({\n open,\n onClose,\n onCreate,\n scopes = DEFAULT_SCOPES,\n title = 'Новый API-ключ',\n submitLabel = 'Создать ключ',\n cancelLabel = 'Отмена',\n}: ApiKeyModalProps) {\n const [name, setName] = useState('');\n const [selected, setSelected] = useState<Record<string, boolean>>({});\n\n const chosen = useMemo(\n () => scopes.filter((s) => selected[s.id]).map((s) => s.id),\n [scopes, selected],\n );\n const canSubmit = name.trim().length > 0 && chosen.length > 0;\n\n const reset = () => {\n setName('');\n setSelected({});\n };\n\n const handleClose = () => {\n reset();\n onClose();\n };\n\n const handleSubmit = () => {\n if (!canSubmit) return;\n onCreate({ name: name.trim(), scopes: chosen });\n reset();\n };\n\n return (\n <Modal\n open={open}\n onClose={handleClose}\n title={title}\n description=\"Ключ будет показан один раз после создания.\"\n size=\"m\"\n footer={\n <>\n <Button variant=\"ghost\" onClick={handleClose}>\n {cancelLabel}\n </Button>\n <Button variant=\"primary\" onClick={handleSubmit} disabled={!canSubmit}>\n {submitLabel}\n </Button>\n </>\n }\n >\n <div className=\"dci-apikey-form\">\n <TextField\n label=\"Название ключа\"\n placeholder=\"например, ci-deploy-bot\"\n required\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n <fieldset className=\"dci-apikey-scopes\">\n <legend className=\"dci-apikey-scopes-legend\">Права доступа</legend>\n {scopes.map((scope) => (\n <div className=\"dci-apikey-scope\" key={scope.id}>\n <Checkbox\n checked={Boolean(selected[scope.id])}\n onChange={(e) => setSelected((prev) => ({ ...prev, [scope.id]: e.target.checked }))}\n label={<span className=\"dci-apikey-scope-name\">{scope.name}</span>}\n description={scope.description}\n />\n </div>\n ))}\n </fieldset>\n </div>\n </Modal>\n );\n}\n"],"mappings":"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"}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.dci-device{cursor:default;position:relative}.dci-device.is-clickable{cursor:pointer}.dci-device-top{align-items:center;gap:7px;margin-bottom:3px;display:flex}.dci-device-dot{border-radius:50%;flex-shrink:0;width:7px;height:7px}.dci-device-dot.s-sync{background:var(--status-ok,#00ffc2)}.dci-device-dot.s-drift{background:var(--status-warn,#f97316)}.dci-device-dot.s-error{background:var(--status-err,#f85149)}.dci-device-dot.s-offline{background:var(--status-off,#6e7681)}.dci-device-name{color:var(--fg1,#f0f6fc);font-size:13px;font-weight:600}.dci-device-status{font-family:var(--font-mono,"JetBrains Mono", monospace);letter-spacing:.08em;text-transform:uppercase;margin-left:auto;font-size:9px}.dci-device-status.s-sync{color:var(--accent-safe,#00aa85)}.dci-device-status.s-drift{color:var(--status-warn,#f97316)}.dci-device-status.s-error{color:var(--status-err,#f85149)}.dci-device-status.s-offline{color:var(--status-off,#6e7681)}.dci-device-ip{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--fg2,#8b949e);margin-bottom:10px;font-size:11px}.dci-device-metahd{justify-content:space-between;align-items:baseline;gap:8px;margin-bottom:3px;display:flex}.dci-device-metric-label{font-family:var(--font-mono,"JetBrains Mono", monospace);letter-spacing:.08em;text-transform:uppercase;color:var(--fg2,#8b949e);font-size:9px}.dci-device-metric-value{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--fg1,#f0f6fc);white-space:nowrap;font-size:11px;font-weight:600}.dci-device-metric-value.is-alert{color:var(--status-warn,#f97316)}.dci-device-spark{align-items:flex-end;gap:2px;height:26px;margin-bottom:8px;display:flex}.dci-device-bar{background:var(--accent-safe,#00aa85);border-radius:1px;flex:1;min-height:2px}.dci-device-bar.is-alert{background:var(--status-warn,#f97316)}.dci-device-tags{gap:4px;display:flex}.dci-device-tag{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--fg2,#8b949e);background:var(--bg,#0d1117);border:1px solid var(--line,#30363d);border-radius:2px;padding:1px 5px;font-size:9px}.dci-pulse-panel{background:var(--panel,#161b22);border:1px solid var(--line,#30363d);border-radius:var(--radius,4px);overflow:hidden}.dci-pulse-head{text-align:left;cursor:pointer;width:100%;color:var(--fg1,#f0f6fc);background:0 0;border:0;align-items:center;gap:18px;padding:16px 18px;transition:background .15s;display:flex}.dci-pulse-head:hover{background:var(--panel-soft,#1d2530)}.dci-pulse-head:focus-visible{outline:2px solid var(--accent,#00ffc2);outline-offset:-2px}.dci-pulse-ring{flex-shrink:0;width:56px;height:56px}.dci-pulse-pct{font-size:26px;font-weight:700;line-height:1}.dci-pulse-label{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--fg2,#8b949e);letter-spacing:.12em;text-transform:uppercase;margin-top:3px;font-size:9px}.dci-pulse-sub{color:var(--fg2,#8b949e);margin-top:7px;font-size:12px}.dci-pulse-sub b{color:var(--status-warn,#f97316);font-weight:600}.dci-pulse-chev{color:var(--fg2,#8b949e);margin-left:auto;transition:transform .2s;display:inline-flex}.dci-pulse-panel.is-open .dci-pulse-chev{transform:rotate(180deg)}.dci-pulse-issues{border-top:1px solid var(--line,#30363d)}.dci-pulse-issues-hd{font-family:var(--font-mono,"JetBrains Mono", monospace);letter-spacing:.12em;text-transform:uppercase;color:var(--fg3,#6e7681);padding:9px 18px 4px;font-size:9px}.dci-pulse-row{border-top:1px solid var(--line-soft,#30363d80);align-items:center;gap:10px;padding:8px 18px;display:flex}.dci-pulse-row-dot{border-radius:50%;flex-shrink:0;width:7px;height:7px}.dci-pulse-row-dot.sev-error{background:var(--status-err,#f85149)}.dci-pulse-row-dot.sev-drift{background:var(--status-warn,#f97316)}.dci-pulse-row-name{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--fg1,#f0f6fc);width:120px;font-size:12px}.dci-pulse-row-reason{color:var(--fg2,#8b949e);flex:1;font-size:12px}.dci-cli{background:var(--bg,#0d1117);border:1px solid var(--line,#30363d);border-radius:var(--radius,4px);align-items:center;gap:10px;padding:9px 12px;display:flex}.dci-cli-icon{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--accent-safe,#00aa85);flex-shrink:0;font-size:12px}.dci-cli-text{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--fg2,#8b949e);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:11px;overflow:hidden}.dci-toast{border-radius:var(--radius,4px);background:var(--panel,#161b22);border:1px solid var(--line,#30363d);border-left:3px solid;align-items:flex-start;gap:10px;padding:10px 14px;display:flex}.dci-toast.v-drift{border-left-color:var(--status-warn,#f97316)}.dci-toast.v-ok{border-left-color:var(--status-ok,#00ffc2)}.dci-toast.v-error{border-left-color:var(--status-err,#f85149)}.dci-toast.v-info{border-left-color:var(--status-info,#58a6ff)}.dci-toast-icon{border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:16px;height:16px;margin-top:1px;display:flex}.dci-toast.v-drift .dci-toast-icon{background:var(--status-warn-soft,#f9731626);color:var(--status-warn,#f97316)}.dci-toast.v-ok .dci-toast-icon{background:var(--accent-soft,#00ffc21f);color:var(--status-ok,#00ffc2)}.dci-toast.v-error .dci-toast-icon{background:var(--status-err-soft,#f8514926);color:var(--status-err,#f85149)}.dci-toast.v-info .dci-toast-icon{background:var(--status-info-soft,#58a6ff26);color:var(--status-info,#58a6ff)}.dci-toast-body{flex:1;min-width:0}.dci-toast-title{color:var(--fg1,#f0f6fc);margin-bottom:2px;font-size:12px;font-weight:600}.dci-toast-desc{color:var(--fg2,#8b949e);font-size:11px;font-weight:300}.dci-toast-close{flex-shrink:0}.dci-apikey-form{flex-direction:column;gap:16px;display:flex}.dci-apikey-scopes{flex-direction:column;gap:8px;display:flex}.dci-apikey-scopes-legend{color:var(--fg1,#f0f6fc);margin-bottom:2px;padding:0;font-size:12px;font-weight:600}.dci-apikey-scope{border:1px solid var(--line,#30363d);border-radius:var(--radius,4px);background:var(--panel-soft,#1d2530);align-items:flex-start;gap:10px;padding:10px 12px;display:flex}.dci-apikey-scope-text{flex-direction:column;gap:2px;display:flex}.dci-apikey-scope-name{font-family:var(--font-mono,"JetBrains Mono", monospace);color:var(--fg1,#f0f6fc);font-size:12px}.dci-apikey-scope-desc{color:var(--fg2,#8b949e);font-size:11px}
|
|
2
|
+
/*$vite$:1*/
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iskra-ui/dci-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Искра.DCI domain components for React — DeviceCard, FleetPulse, CliRow, DriftToast, ApiKeyModal — built on @iskra-ui/react.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./styles.css": "./dist/styles.css"
|
|
19
|
+
},
|
|
20
|
+
"sideEffects": [
|
|
21
|
+
"**/*.css"
|
|
22
|
+
],
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react": ">=18",
|
|
25
|
+
"react-dom": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@iskra-ui/core": "0.1.0",
|
|
29
|
+
"@iskra-ui/icons": "0.1.0",
|
|
30
|
+
"@iskra-ui/react": "0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@storybook/react-vite": "^10.4.0",
|
|
34
|
+
"@testing-library/jest-dom": "^6.9.0",
|
|
35
|
+
"@testing-library/react": "^16.0.0",
|
|
36
|
+
"@testing-library/user-event": "^14.6.0",
|
|
37
|
+
"@types/react": "^19.2.0",
|
|
38
|
+
"@types/react-dom": "^19.2.0",
|
|
39
|
+
"@vitejs/plugin-react": "^6.0.0",
|
|
40
|
+
"jsdom": "^29.0.0",
|
|
41
|
+
"react": "^19.2.0",
|
|
42
|
+
"react-dom": "^19.2.0",
|
|
43
|
+
"typescript": "^6.0.0",
|
|
44
|
+
"vite": "^8.0.0",
|
|
45
|
+
"vitest": "^4.1.0",
|
|
46
|
+
"@iskra-ui/tsconfig": "0.1.0"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public",
|
|
50
|
+
"provenance": true
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.build.json",
|
|
54
|
+
"dev": "vite build --watch",
|
|
55
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
56
|
+
"test": "vitest run"
|
|
57
|
+
}
|
|
58
|
+
}
|