@hanzo/ui 8.0.7 → 8.0.8
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/dist/ThemeToggleNext-7727UR5W.js +4 -0
- package/dist/ThemeToggleNext-7727UR5W.js.map +1 -0
- package/dist/ThemeToggleNext-ICB5KL5J.cjs +19 -0
- package/dist/ThemeToggleNext-ICB5KL5J.cjs.map +1 -0
- package/dist/billing.cjs +15 -0
- package/dist/billing.cjs.map +1 -0
- package/{types → dist}/billing.d.ts +0 -1
- package/dist/billing.js +4 -0
- package/dist/billing.js.map +1 -0
- package/dist/canvas.cjs +15 -0
- package/dist/canvas.cjs.map +1 -0
- package/dist/canvas.d.ts +1 -0
- package/dist/canvas.js +4 -0
- package/dist/canvas.js.map +1 -0
- package/{types → dist}/cd/layout.d.ts +0 -1
- package/{types → dist}/cd/status.d.ts +0 -1
- package/{types → dist}/cd/time.d.ts +0 -1
- package/{types → dist}/cd/types.d.ts +0 -1
- package/dist/chunk-42CU5GSF.js +98 -0
- package/dist/chunk-42CU5GSF.js.map +1 -0
- package/dist/chunk-GDGVXU7W.js +1999 -0
- package/dist/chunk-GDGVXU7W.js.map +1 -0
- package/dist/chunk-HSPMQQVJ.cjs +2066 -0
- package/dist/chunk-HSPMQQVJ.cjs.map +1 -0
- package/dist/chunk-YBXVUV7P.cjs +103 -0
- package/dist/chunk-YBXVUV7P.cjs.map +1 -0
- package/dist/dashboard.cjs +15 -0
- package/dist/dashboard.cjs.map +1 -0
- package/dist/dashboard.d.ts +1 -0
- package/dist/dashboard.js +4 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/data.cjs +15 -0
- package/dist/data.cjs.map +1 -0
- package/dist/data.d.ts +1 -0
- package/dist/data.js +4 -0
- package/dist/data.js.map +1 -0
- package/dist/gitops.cjs +15 -0
- package/dist/gitops.cjs.map +1 -0
- package/dist/gitops.d.ts +1 -0
- package/dist/gitops.js +4 -0
- package/dist/gitops.js.map +1 -0
- package/dist/index.cjs +291 -0
- package/dist/index.cjs.map +1 -0
- package/{types → dist}/index.d.ts +0 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/network.cjs +15 -0
- package/dist/network.cjs.map +1 -0
- package/{types → dist}/network.d.ts +0 -1
- package/dist/network.js +4 -0
- package/dist/network.js.map +1 -0
- package/dist/primitives/bases/data/index.cjs +15 -0
- package/dist/primitives/bases/data/index.cjs.map +1 -0
- package/dist/primitives/bases/data/index.d.ts +1 -0
- package/dist/primitives/bases/data/index.js +4 -0
- package/dist/primitives/bases/data/index.js.map +1 -0
- package/{types → dist}/product/AppHeader.d.ts +0 -1
- package/{types → dist}/product/BrandMark.d.ts +0 -1
- package/{types → dist}/product/Charts.d.ts +0 -1
- package/{types → dist}/product/ComboBox.d.ts +0 -1
- package/{types → dist}/product/DataTable.d.ts +0 -1
- package/{types → dist}/product/Donut.d.ts +0 -1
- package/{types → dist}/product/EmptyState.d.ts +0 -1
- package/{types → dist}/product/FadeIn.d.ts +0 -1
- package/{types → dist}/product/Field.d.ts +0 -1
- package/{types → dist}/product/HanzoMark.d.ts +0 -1
- package/{types → dist}/product/Metric.d.ts +0 -1
- package/{types → dist}/product/OrgSwitcher.d.ts +0 -1
- package/{types → dist}/product/PageHeader.d.ts +0 -1
- package/{types → dist}/product/PrimaryButton.d.ts +0 -1
- package/{types → dist}/product/ProductIcon.d.ts +0 -1
- package/{types → dist}/product/ProviderLogo.d.ts +0 -1
- package/{types → dist}/product/Reorder.d.ts +0 -1
- package/{types → dist}/product/SelectMenu.d.ts +6 -8
- package/{types → dist}/product/SlideOver.d.ts +0 -1
- package/{types → dist}/product/StatusTag.d.ts +0 -1
- package/{types → dist}/product/ThemeToggle.d.ts +0 -1
- package/{types → dist}/product/ThemeToggleNext.d.ts +0 -1
- package/{types → dist}/product/Toast.d.ts +0 -1
- package/{types → dist}/product/color.d.ts +0 -1
- package/{types → dist}/product/combobox/filter.d.ts +0 -1
- package/dist/product/index.cjs +278 -0
- package/dist/product/index.cjs.map +1 -0
- package/{types → dist}/product/index.d.ts +0 -1
- package/dist/product/index.js +5 -0
- package/dist/product/index.js.map +1 -0
- package/{types → dist}/product/menu/ContextMenu.d.ts +3 -6
- package/dist/product/menu/DropdownMenu.d.ts +29 -0
- package/dist/product/menu/FloatingMenu.d.ts +36 -0
- package/{types → dist}/product/menu/index.d.ts +1 -1
- package/{types → dist}/product/menu/items.d.ts +0 -1
- package/{types → dist}/product/menu/portal-theme.d.ts +0 -1
- package/{types → dist}/product/menu/roving.d.ts +0 -1
- package/{types → dist}/product/scope.d.ts +0 -1
- package/{types → dist}/product/surfaces.data.d.ts +0 -1
- package/dist/usage.cjs +15 -0
- package/dist/usage.cjs.map +1 -0
- package/dist/usage.d.ts +1 -0
- package/dist/usage.js +4 -0
- package/dist/usage.js.map +1 -0
- package/dist/wallet.cjs +15 -0
- package/dist/wallet.cjs.map +1 -0
- package/{types → dist}/wallet.d.ts +0 -1
- package/dist/wallet.js +4 -0
- package/dist/wallet.js.map +1 -0
- package/package.json +54 -32
- package/src/billing.ts +0 -9
- package/src/canvas.ts +0 -11
- package/src/cd/layout.ts +0 -184
- package/src/cd/status.ts +0 -158
- package/src/cd/time.ts +0 -52
- package/src/cd/types.ts +0 -318
- package/src/dashboard.ts +0 -8
- package/src/data.ts +0 -12
- package/src/gitops.ts +0 -5
- package/src/gui-env.d.ts +0 -27
- package/src/index.ts +0 -22
- package/src/network.ts +0 -11
- package/src/primitives/bases/data/index.ts +0 -13
- package/src/product/AppHeader.tsx +0 -183
- package/src/product/BrandMark.tsx +0 -27
- package/src/product/Charts.tsx +0 -471
- package/src/product/ComboBox.tsx +0 -127
- package/src/product/DataTable.tsx +0 -99
- package/src/product/Donut.tsx +0 -83
- package/src/product/EmptyState.tsx +0 -129
- package/src/product/FadeIn.tsx +0 -38
- package/src/product/Field.tsx +0 -160
- package/src/product/HanzoMark.tsx +0 -31
- package/src/product/Metric.tsx +0 -253
- package/src/product/OrgSwitcher.tsx +0 -332
- package/src/product/PageHeader.tsx +0 -31
- package/src/product/PrimaryButton.tsx +0 -17
- package/src/product/ProductIcon.tsx +0 -61
- package/src/product/ProviderLogo.tsx +0 -137
- package/src/product/Reorder.test.ts +0 -41
- package/src/product/Reorder.tsx +0 -110
- package/src/product/SelectMenu.tsx +0 -80
- package/src/product/SlideOver.tsx +0 -197
- package/src/product/StatusTag.tsx +0 -49
- package/src/product/ThemeToggle.tsx +0 -135
- package/src/product/ThemeToggleNext.tsx +0 -27
- package/src/product/Toast.tsx +0 -166
- package/src/product/color.ts +0 -17
- package/src/product/combobox/filter.test.ts +0 -51
- package/src/product/combobox/filter.ts +0 -39
- package/src/product/index.ts +0 -76
- package/src/product/menu/ContextMenu.tsx +0 -114
- package/src/product/menu/DropdownMenu.tsx +0 -76
- package/src/product/menu/index.ts +0 -15
- package/src/product/menu/items.tsx +0 -230
- package/src/product/menu/portal-theme.tsx +0 -33
- package/src/product/menu/roving.ts +0 -34
- package/src/product/scope.test.ts +0 -92
- package/src/product/scope.ts +0 -123
- package/src/product/surfaces.data.ts +0 -42
- package/src/usage.ts +0 -8
- package/src/wallet.ts +0 -11
- package/types/billing.d.ts.map +0 -1
- package/types/canvas.d.ts +0 -2
- package/types/canvas.d.ts.map +0 -1
- package/types/cd/layout.d.ts.map +0 -1
- package/types/cd/status.d.ts.map +0 -1
- package/types/cd/time.d.ts.map +0 -1
- package/types/cd/types.d.ts.map +0 -1
- package/types/dashboard.d.ts +0 -2
- package/types/dashboard.d.ts.map +0 -1
- package/types/data.d.ts +0 -2
- package/types/data.d.ts.map +0 -1
- package/types/gitops.d.ts +0 -2
- package/types/gitops.d.ts.map +0 -1
- package/types/index.d.ts.map +0 -1
- package/types/network.d.ts.map +0 -1
- package/types/primitives/bases/data/index.d.ts +0 -2
- package/types/primitives/bases/data/index.d.ts.map +0 -1
- package/types/product/AppHeader.d.ts.map +0 -1
- package/types/product/BrandMark.d.ts.map +0 -1
- package/types/product/Charts.d.ts.map +0 -1
- package/types/product/ComboBox.d.ts.map +0 -1
- package/types/product/DataTable.d.ts.map +0 -1
- package/types/product/Donut.d.ts.map +0 -1
- package/types/product/EmptyState.d.ts.map +0 -1
- package/types/product/FadeIn.d.ts.map +0 -1
- package/types/product/Field.d.ts.map +0 -1
- package/types/product/HanzoMark.d.ts.map +0 -1
- package/types/product/Metric.d.ts.map +0 -1
- package/types/product/OrgSwitcher.d.ts.map +0 -1
- package/types/product/PageHeader.d.ts.map +0 -1
- package/types/product/PrimaryButton.d.ts.map +0 -1
- package/types/product/ProductIcon.d.ts.map +0 -1
- package/types/product/ProviderLogo.d.ts.map +0 -1
- package/types/product/Reorder.d.ts.map +0 -1
- package/types/product/SelectMenu.d.ts.map +0 -1
- package/types/product/SlideOver.d.ts.map +0 -1
- package/types/product/StatusTag.d.ts.map +0 -1
- package/types/product/ThemeToggle.d.ts.map +0 -1
- package/types/product/ThemeToggleNext.d.ts.map +0 -1
- package/types/product/Toast.d.ts.map +0 -1
- package/types/product/color.d.ts.map +0 -1
- package/types/product/combobox/filter.d.ts.map +0 -1
- package/types/product/index.d.ts.map +0 -1
- package/types/product/menu/ContextMenu.d.ts.map +0 -1
- package/types/product/menu/DropdownMenu.d.ts +0 -34
- package/types/product/menu/DropdownMenu.d.ts.map +0 -1
- package/types/product/menu/index.d.ts.map +0 -1
- package/types/product/menu/items.d.ts.map +0 -1
- package/types/product/menu/portal-theme.d.ts.map +0 -1
- package/types/product/menu/roving.d.ts.map +0 -1
- package/types/product/scope.d.ts.map +0 -1
- package/types/product/surfaces.data.d.ts.map +0 -1
- package/types/usage.d.ts +0 -2
- package/types/usage.d.ts.map +0 -1
- package/types/wallet.d.ts.map +0 -1
- /package/{src → dist}/styles/hanzo-motion.css +0 -0
package/package.json
CHANGED
|
@@ -1,69 +1,90 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/ui",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Hanzo UI \u2014 the one cross-platform component library on @hanzo/gui. The product/app layer (charts, metrics, page headers, status tags, rich empty states, combobox, slide-over, toasts, drag-reorder, labeled field rows, provider/product marks) + the metadata-driven record layer (@hanzo/data: RecordsView, DataTable, board, typed field editors) + the calm dark-first tokens and motion. Presentational, host-agnostic (data/effects injected), clean-room. Web + native (iOS) + desktop.",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"types": "./
|
|
9
|
-
"
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"require": "./dist/index.cjs",
|
|
11
|
+
"default": "./dist/index.js"
|
|
10
12
|
},
|
|
11
13
|
"./product": {
|
|
12
|
-
"types": "./
|
|
13
|
-
"
|
|
14
|
+
"types": "./dist/product/index.d.ts",
|
|
15
|
+
"import": "./dist/product/index.js",
|
|
16
|
+
"require": "./dist/product/index.cjs",
|
|
17
|
+
"default": "./dist/product/index.js"
|
|
14
18
|
},
|
|
15
19
|
"./data": {
|
|
16
|
-
"types": "./
|
|
17
|
-
"
|
|
20
|
+
"types": "./dist/data.d.ts",
|
|
21
|
+
"import": "./dist/data.js",
|
|
22
|
+
"require": "./dist/data.cjs",
|
|
23
|
+
"default": "./dist/data.js"
|
|
18
24
|
},
|
|
19
25
|
"./primitives/bases/data": {
|
|
20
|
-
"types": "./
|
|
21
|
-
"
|
|
26
|
+
"types": "./dist/primitives/bases/data/index.d.ts",
|
|
27
|
+
"import": "./dist/primitives/bases/data/index.js",
|
|
28
|
+
"require": "./dist/primitives/bases/data/index.cjs",
|
|
29
|
+
"default": "./dist/primitives/bases/data/index.js"
|
|
22
30
|
},
|
|
23
31
|
"./gitops": {
|
|
24
|
-
"types": "./
|
|
25
|
-
"
|
|
32
|
+
"types": "./dist/gitops.d.ts",
|
|
33
|
+
"import": "./dist/gitops.js",
|
|
34
|
+
"require": "./dist/gitops.cjs",
|
|
35
|
+
"default": "./dist/gitops.js"
|
|
26
36
|
},
|
|
27
37
|
"./canvas": {
|
|
28
|
-
"types": "./
|
|
29
|
-
"
|
|
38
|
+
"types": "./dist/canvas.d.ts",
|
|
39
|
+
"import": "./dist/canvas.js",
|
|
40
|
+
"require": "./dist/canvas.cjs",
|
|
41
|
+
"default": "./dist/canvas.js"
|
|
30
42
|
},
|
|
31
43
|
"./wallet": {
|
|
32
|
-
"types": "./
|
|
33
|
-
"
|
|
44
|
+
"types": "./dist/wallet.d.ts",
|
|
45
|
+
"import": "./dist/wallet.js",
|
|
46
|
+
"require": "./dist/wallet.cjs",
|
|
47
|
+
"default": "./dist/wallet.js"
|
|
34
48
|
},
|
|
35
49
|
"./network": {
|
|
36
|
-
"types": "./
|
|
37
|
-
"
|
|
50
|
+
"types": "./dist/network.d.ts",
|
|
51
|
+
"import": "./dist/network.js",
|
|
52
|
+
"require": "./dist/network.cjs",
|
|
53
|
+
"default": "./dist/network.js"
|
|
38
54
|
},
|
|
39
55
|
"./billing": {
|
|
40
|
-
"types": "./
|
|
41
|
-
"
|
|
56
|
+
"types": "./dist/billing.d.ts",
|
|
57
|
+
"import": "./dist/billing.js",
|
|
58
|
+
"require": "./dist/billing.cjs",
|
|
59
|
+
"default": "./dist/billing.js"
|
|
42
60
|
},
|
|
43
61
|
"./dashboard": {
|
|
44
|
-
"types": "./
|
|
45
|
-
"
|
|
62
|
+
"types": "./dist/dashboard.d.ts",
|
|
63
|
+
"import": "./dist/dashboard.js",
|
|
64
|
+
"require": "./dist/dashboard.cjs",
|
|
65
|
+
"default": "./dist/dashboard.js"
|
|
46
66
|
},
|
|
47
67
|
"./usage": {
|
|
48
|
-
"types": "./
|
|
49
|
-
"
|
|
68
|
+
"types": "./dist/usage.d.ts",
|
|
69
|
+
"import": "./dist/usage.js",
|
|
70
|
+
"require": "./dist/usage.cjs",
|
|
71
|
+
"default": "./dist/usage.js"
|
|
50
72
|
},
|
|
51
|
-
"./styles/motion.css": "./
|
|
73
|
+
"./styles/motion.css": "./dist/styles/hanzo-motion.css",
|
|
52
74
|
"./package.json": "./package.json"
|
|
53
75
|
},
|
|
54
|
-
"main": "./
|
|
55
|
-
"module": "./
|
|
56
|
-
"types": "./
|
|
76
|
+
"main": "./dist/index.cjs",
|
|
77
|
+
"module": "./dist/index.js",
|
|
78
|
+
"types": "./dist/index.d.ts",
|
|
57
79
|
"sideEffects": [
|
|
58
80
|
"**/*.css"
|
|
59
81
|
],
|
|
60
82
|
"files": [
|
|
61
|
-
"
|
|
62
|
-
"types"
|
|
83
|
+
"dist"
|
|
63
84
|
],
|
|
64
85
|
"scripts": {
|
|
65
|
-
"build": "tsc -p tsconfig.build.json",
|
|
66
|
-
"clean": "rm -rf types",
|
|
86
|
+
"build": "tsup && tsc -p tsconfig.build.json && mkdir -p dist/styles && cp src/styles/hanzo-motion.css dist/styles/hanzo-motion.css && node scripts/add-use-client.mjs",
|
|
87
|
+
"clean": "rm -rf dist types",
|
|
67
88
|
"prepack": "pnpm run build",
|
|
68
89
|
"tc": "tsc --noEmit",
|
|
69
90
|
"typecheck": "tsc --noEmit",
|
|
@@ -120,7 +141,8 @@
|
|
|
120
141
|
"react-dom": "^19.0.0",
|
|
121
142
|
"typescript": "^5.7.2",
|
|
122
143
|
"vitest": "^4.1.8",
|
|
123
|
-
"react-native-web": "^0.21.2"
|
|
144
|
+
"react-native-web": "^0.21.2",
|
|
145
|
+
"tsup": "^8.5.1"
|
|
124
146
|
},
|
|
125
147
|
"publishConfig": {
|
|
126
148
|
"access": "public"
|
package/src/billing.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// @hanzo/ui/billing — the shared billing surface, re-exported from its home
|
|
2
|
-
// module @hanzo/ui-shadcn/billing. `CreditModal` presents trial + prepaid credit
|
|
3
|
-
// buckets with an injected top-up handler (no payment logic in the component).
|
|
4
|
-
// Thin subpath so every console shows the same credit UI:
|
|
5
|
-
//
|
|
6
|
-
// import { CreditModal } from '@hanzo/ui/billing'
|
|
7
|
-
//
|
|
8
|
-
// Optional peer — only pulled when the subpath is used.
|
|
9
|
-
export * from '@hanzo/ui-shadcn/billing'
|
package/src/canvas.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// @hanzo/ui/canvas — the PaaS project canvas, re-exported from its home package
|
|
2
|
-
// @hanzo/canvas (a Railway-grade pannable/zoomable board of service nodes with
|
|
3
|
-
// live status, metric sparklines, deploy timelines, an environment switcher and
|
|
4
|
-
// a service detail drawer). Kept as a thin subpath so a console can
|
|
5
|
-
//
|
|
6
|
-
// import { ProjectCanvas, ServiceNode, ServiceStatusBadge, DeployTimeline,
|
|
7
|
-
// EnvSwitcher, ServiceDetailDrawer } from '@hanzo/ui/canvas'
|
|
8
|
-
//
|
|
9
|
-
// while the code lives once in @hanzo/canvas. Optional peer — only pulled when
|
|
10
|
-
// the subpath is used.
|
|
11
|
-
export * from '@hanzo/canvas'
|
package/src/cd/layout.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Deterministic layered graph layout — pure, no React, no DOM, unit-tested. This
|
|
3
|
-
* is the dependency-free equivalent of the GitOps engine UI's dagre `rankdir:LR`
|
|
4
|
-
* pass: resources flow left→right by ownership depth, each tier a clean column.
|
|
5
|
-
*
|
|
6
|
-
* Three folds:
|
|
7
|
-
* 1. columns — longest-path layering (Kahn topological order). A root (no
|
|
8
|
-
* incoming edge) sits in column 0; every other node one column right of its
|
|
9
|
-
* deepest parent. Cycles degrade gracefully (a child keeps its best column),
|
|
10
|
-
* so a malformed graph can never wedge the layout.
|
|
11
|
-
* 2. order — within a column, nodes are ordered by the barycentre of their
|
|
12
|
-
* parents' rows (then name), so children cluster under their owner and edge
|
|
13
|
-
* crossings stay low — dagre's crossing-reduction, cheaply.
|
|
14
|
-
* 3. place — nodes stack top-to-bottom at their own height (pods are taller
|
|
15
|
-
* than controllers) with a fixed gap, and each column is vertically centred
|
|
16
|
-
* on a shared axis so tiers read as balanced columns.
|
|
17
|
-
*
|
|
18
|
-
* The same graph always yields byte-identical positions.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
export interface LayoutNode {
|
|
22
|
-
id: string
|
|
23
|
-
/** Rendered height in px (pods are taller than controllers). */
|
|
24
|
-
h: number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface LayoutEdge {
|
|
28
|
-
source: string
|
|
29
|
-
target: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface LayoutOptions {
|
|
33
|
-
/** Uniform node width in px (x is placed on a fixed column pitch). */
|
|
34
|
-
nodeWidth?: number
|
|
35
|
-
/** Horizontal gap between a column's right edge and the next column. */
|
|
36
|
-
columnGap?: number
|
|
37
|
-
/** Vertical gap between stacked nodes in a column. */
|
|
38
|
-
rowGap?: number
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface PositionedNode {
|
|
42
|
-
id: string
|
|
43
|
-
/** Top-left corner, px. */
|
|
44
|
-
x: number
|
|
45
|
-
y: number
|
|
46
|
-
w: number
|
|
47
|
-
h: number
|
|
48
|
-
col: number
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface GraphLayout {
|
|
52
|
-
nodes: PositionedNode[]
|
|
53
|
-
/** Content bounds — the transformed layer's intrinsic size. */
|
|
54
|
-
width: number
|
|
55
|
-
height: number
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const DEFAULTS = { nodeWidth: 260, columnGap: 68, rowGap: 22 } as const
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Assign each node a column via longest-path layering over the edges. Processes
|
|
62
|
-
* nodes in Kahn topological order; an edge into an unknown/cyclic parent is
|
|
63
|
-
* skipped so a cycle never wedges the pass.
|
|
64
|
-
*/
|
|
65
|
-
function assignColumns(ids: string[], edges: LayoutEdge[]): Map<string, number> {
|
|
66
|
-
const present = new Set(ids)
|
|
67
|
-
const outgoing = new Map<string, string[]>()
|
|
68
|
-
const indeg = new Map<string, number>()
|
|
69
|
-
for (const id of ids) {
|
|
70
|
-
outgoing.set(id, [])
|
|
71
|
-
indeg.set(id, 0)
|
|
72
|
-
}
|
|
73
|
-
for (const e of edges) {
|
|
74
|
-
if (!present.has(e.source) || !present.has(e.target) || e.source === e.target) continue
|
|
75
|
-
outgoing.get(e.source)!.push(e.target)
|
|
76
|
-
indeg.set(e.target, (indeg.get(e.target) ?? 0) + 1)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const column = new Map<string, number>()
|
|
80
|
-
for (const id of ids) column.set(id, 0)
|
|
81
|
-
|
|
82
|
-
const remaining = new Map(indeg)
|
|
83
|
-
const queue = ids.filter((id) => (remaining.get(id) ?? 0) === 0).sort()
|
|
84
|
-
const seen = new Set<string>()
|
|
85
|
-
while (queue.length) {
|
|
86
|
-
const u = queue.shift()!
|
|
87
|
-
if (seen.has(u)) continue
|
|
88
|
-
seen.add(u)
|
|
89
|
-
const cu = column.get(u) ?? 0
|
|
90
|
-
for (const v of outgoing.get(u) ?? []) {
|
|
91
|
-
if (cu + 1 > (column.get(v) ?? 0)) column.set(v, cu + 1)
|
|
92
|
-
const left = (remaining.get(v) ?? 0) - 1
|
|
93
|
-
remaining.set(v, left)
|
|
94
|
-
if (left <= 0 && !seen.has(v)) queue.push(v)
|
|
95
|
-
}
|
|
96
|
-
queue.sort()
|
|
97
|
-
}
|
|
98
|
-
return column
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Lay a resource graph out into centred LR columns. Returns one positioned node
|
|
103
|
-
* per input node (input order preserved in the result array) plus content bounds.
|
|
104
|
-
*/
|
|
105
|
-
export function layoutTree(
|
|
106
|
-
nodes: LayoutNode[],
|
|
107
|
-
edges: LayoutEdge[],
|
|
108
|
-
opts: LayoutOptions = {}
|
|
109
|
-
): GraphLayout {
|
|
110
|
-
const nodeWidth = opts.nodeWidth ?? DEFAULTS.nodeWidth
|
|
111
|
-
const columnGap = opts.columnGap ?? DEFAULTS.columnGap
|
|
112
|
-
const rowGap = opts.rowGap ?? DEFAULTS.rowGap
|
|
113
|
-
|
|
114
|
-
const ids = nodes.map((n) => n.id)
|
|
115
|
-
const heightOf = new Map(nodes.map((n) => [n.id, n.h]))
|
|
116
|
-
const column = assignColumns(ids, edges)
|
|
117
|
-
|
|
118
|
-
// Parents per node (for the barycentre ordering).
|
|
119
|
-
const parents = new Map<string, string[]>()
|
|
120
|
-
for (const id of ids) parents.set(id, [])
|
|
121
|
-
const present = new Set(ids)
|
|
122
|
-
for (const e of edges) {
|
|
123
|
-
if (!present.has(e.source) || !present.has(e.target) || e.source === e.target) continue
|
|
124
|
-
parents.get(e.target)!.push(e.source)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Group ids by column, preserving input order as the stable tie-break.
|
|
128
|
-
const inputOrder = new Map(ids.map((id, i) => [id, i]))
|
|
129
|
-
const byColumn = new Map<number, string[]>()
|
|
130
|
-
for (const id of ids) {
|
|
131
|
-
const c = column.get(id) ?? 0
|
|
132
|
-
const list = byColumn.get(c)
|
|
133
|
-
if (list) list.push(id)
|
|
134
|
-
else byColumn.set(c, [id])
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Order each column left→right by the barycentre of parents' rows in the
|
|
138
|
-
// previous column, so children sit under their owner.
|
|
139
|
-
const rowOrder = new Map<string, number>()
|
|
140
|
-
const sortedColumns = Array.from(byColumn.keys()).sort((a, b) => a - b)
|
|
141
|
-
for (const c of sortedColumns) {
|
|
142
|
-
const list = byColumn.get(c)!
|
|
143
|
-
list.sort((a, b) => {
|
|
144
|
-
const key = (id: string): number => {
|
|
145
|
-
const ps = parents.get(id) ?? []
|
|
146
|
-
const rows = ps.map((p) => rowOrder.get(p)).filter((r): r is number => r != null)
|
|
147
|
-
return rows.length ? rows.reduce((s, r) => s + r, 0) / rows.length : Number.POSITIVE_INFINITY
|
|
148
|
-
}
|
|
149
|
-
const ka = key(a)
|
|
150
|
-
const kb = key(b)
|
|
151
|
-
if (ka !== kb) return ka - kb
|
|
152
|
-
return (inputOrder.get(a) ?? 0) - (inputOrder.get(b) ?? 0)
|
|
153
|
-
})
|
|
154
|
-
list.forEach((id, i) => rowOrder.set(id, i))
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Column heights → the shared vertical axis (tallest column centred).
|
|
158
|
-
const columnHeight = new Map<number, number>()
|
|
159
|
-
for (const [c, list] of byColumn) {
|
|
160
|
-
const total = list.reduce((s, id) => s + (heightOf.get(id) ?? 0), 0) + Math.max(0, list.length - 1) * rowGap
|
|
161
|
-
columnHeight.set(c, total)
|
|
162
|
-
}
|
|
163
|
-
const axis = Math.max(0, ...Array.from(columnHeight.values())) / 2
|
|
164
|
-
|
|
165
|
-
const pos = new Map<string, { x: number; y: number }>()
|
|
166
|
-
for (const c of sortedColumns) {
|
|
167
|
-
const list = byColumn.get(c)!
|
|
168
|
-
const x = c * (nodeWidth + columnGap)
|
|
169
|
-
let y = axis - (columnHeight.get(c) ?? 0) / 2
|
|
170
|
-
for (const id of list) {
|
|
171
|
-
pos.set(id, { x, y })
|
|
172
|
-
y += (heightOf.get(id) ?? 0) + rowGap
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const positioned: PositionedNode[] = nodes.map((n) => {
|
|
177
|
-
const p = pos.get(n.id) ?? { x: 0, y: 0 }
|
|
178
|
-
return { id: n.id, x: p.x, y: p.y, w: nodeWidth, h: n.h, col: column.get(n.id) ?? 0 }
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
const width = positioned.reduce((m, n) => Math.max(m, n.x + n.w), 0)
|
|
182
|
-
const height = positioned.reduce((m, n) => Math.max(m, n.y + n.h), 0)
|
|
183
|
-
return { nodes: positioned, width, height }
|
|
184
|
-
}
|
package/src/cd/status.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CD status → colour, tone, label, priority — the ONE semantic mapping, pure and
|
|
3
|
-
* unit-tested. Everything visual reads from here so a health/sync verdict looks
|
|
4
|
-
* identical in a pill, a tree node's accent, a mini-bar, and the minimap.
|
|
5
|
-
*
|
|
6
|
-
* The hues keep the GitOps meaning (green = healthy/synced, amber = out-of-sync /
|
|
7
|
-
* missing, red = degraded, blue = progressing, purple = suspended, grey =
|
|
8
|
-
* unknown) but are re-tuned for a dark-first surface so they stay legible on
|
|
9
|
-
* near-black without the washed-out look of the light-theme originals.
|
|
10
|
-
*/
|
|
11
|
-
import type { HealthStatus, OperationPhase, PodPhase, SyncStatus } from './types'
|
|
12
|
-
|
|
13
|
-
/** A coarse tone bucket, shared with the rest of @hanzo/ui's tag vocabulary. */
|
|
14
|
-
export type StatusTone = 'green' | 'yellow' | 'red' | 'blue' | 'purple' | 'neutral'
|
|
15
|
-
|
|
16
|
-
/** The concrete swatch a status renders in: dot/text hue + a soft chip fill. */
|
|
17
|
-
export interface StatusColor {
|
|
18
|
-
/** The saturated hue — the dot, the accent bar, the pill text. */
|
|
19
|
-
hue: string
|
|
20
|
-
tone: StatusTone
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Dark-tuned semantic hues. Bright enough to read as the pill's own text on a
|
|
24
|
-
// near-black surface; the soft chip fill is derived from these at low alpha.
|
|
25
|
-
const HUES: Record<StatusTone, string> = {
|
|
26
|
-
green: '#22c55e',
|
|
27
|
-
yellow: '#f5b544',
|
|
28
|
-
red: '#f4636e',
|
|
29
|
-
blue: '#38a0f5',
|
|
30
|
-
purple: '#a684f5',
|
|
31
|
-
neutral: '#8b96a5',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const HEALTH_TONE: Record<HealthStatus, StatusTone> = {
|
|
35
|
-
Healthy: 'green',
|
|
36
|
-
Progressing: 'blue',
|
|
37
|
-
Degraded: 'red',
|
|
38
|
-
Suspended: 'purple',
|
|
39
|
-
Missing: 'yellow',
|
|
40
|
-
Unknown: 'neutral',
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const SYNC_TONE: Record<SyncStatus, StatusTone> = {
|
|
44
|
-
Synced: 'green',
|
|
45
|
-
OutOfSync: 'yellow',
|
|
46
|
-
Unknown: 'neutral',
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const OPERATION_TONE: Record<OperationPhase, StatusTone> = {
|
|
50
|
-
Succeeded: 'green',
|
|
51
|
-
Running: 'blue',
|
|
52
|
-
Pending: 'blue',
|
|
53
|
-
Terminating: 'red',
|
|
54
|
-
Failed: 'red',
|
|
55
|
-
Error: 'red',
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const POD_TONE: Record<PodPhase, StatusTone> = {
|
|
59
|
-
Running: 'green',
|
|
60
|
-
Succeeded: 'green',
|
|
61
|
-
Pending: 'blue',
|
|
62
|
-
Failed: 'red',
|
|
63
|
-
Unknown: 'neutral',
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Worst-first ordering (lower = worse), so a rollup surfaces the most broken
|
|
68
|
-
* verdict and a sort puts problems on top — matching the GitOps engine's own
|
|
69
|
-
* health precedence.
|
|
70
|
-
*/
|
|
71
|
-
export const HEALTH_PRIORITY: Record<HealthStatus, number> = {
|
|
72
|
-
Missing: 0,
|
|
73
|
-
Degraded: 1,
|
|
74
|
-
Unknown: 2,
|
|
75
|
-
Progressing: 3,
|
|
76
|
-
Suspended: 4,
|
|
77
|
-
Healthy: 5,
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export const SYNC_PRIORITY: Record<SyncStatus, number> = {
|
|
81
|
-
OutOfSync: 0,
|
|
82
|
-
Unknown: 1,
|
|
83
|
-
Synced: 2,
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const HEALTH_SET = new Set<string>(Object.keys(HEALTH_TONE))
|
|
87
|
-
const SYNC_SET = new Set<string>(Object.keys(SYNC_TONE))
|
|
88
|
-
|
|
89
|
-
/** Coerce a free-form backend string into a known health code (fails to Unknown). */
|
|
90
|
-
export function normalizeHealth(s?: string): HealthStatus {
|
|
91
|
-
return s && HEALTH_SET.has(s) ? (s as HealthStatus) : 'Unknown'
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Coerce a free-form backend string into a known sync code (fails to Unknown). */
|
|
95
|
-
export function normalizeSync(s?: string): SyncStatus {
|
|
96
|
-
return s && SYNC_SET.has(s) ? (s as SyncStatus) : 'Unknown'
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function healthColor(status: HealthStatus): StatusColor {
|
|
100
|
-
const tone = HEALTH_TONE[status] ?? 'neutral'
|
|
101
|
-
return { hue: HUES[tone], tone }
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function syncColor(status: SyncStatus): StatusColor {
|
|
105
|
-
const tone = SYNC_TONE[status] ?? 'neutral'
|
|
106
|
-
return { hue: HUES[tone], tone }
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function operationColor(phase: OperationPhase): StatusColor {
|
|
110
|
-
const tone = OPERATION_TONE[phase] ?? 'neutral'
|
|
111
|
-
return { hue: HUES[tone], tone }
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function podColor(phase: PodPhase): StatusColor {
|
|
115
|
-
const tone = POD_TONE[phase] ?? 'neutral'
|
|
116
|
-
return { hue: HUES[tone], tone }
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** The saturated hue for a tone (for callers that already have a tone). */
|
|
120
|
-
export function toneHue(tone: StatusTone): string {
|
|
121
|
-
return HUES[tone]
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Roll a set of resource healths up to the single verdict that best describes
|
|
126
|
-
* the whole — the worst one present. Empty ⇒ `Unknown` (honest, never `Healthy`).
|
|
127
|
-
*/
|
|
128
|
-
export function worstHealth(statuses: HealthStatus[]): HealthStatus {
|
|
129
|
-
if (statuses.length === 0) return 'Unknown'
|
|
130
|
-
return statuses.reduce((worst, s) =>
|
|
131
|
-
HEALTH_PRIORITY[s] < HEALTH_PRIORITY[worst] ? s : worst
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/** Roll a set of sync verdicts up to one — OutOfSync wins, then Unknown. */
|
|
136
|
-
export function worstSync(statuses: SyncStatus[]): SyncStatus {
|
|
137
|
-
if (statuses.length === 0) return 'Unknown'
|
|
138
|
-
return statuses.reduce((worst, s) =>
|
|
139
|
-
SYNC_PRIORITY[s] < SYNC_PRIORITY[worst] ? s : worst
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Parse a `#rgb`/`#rrggbb` hue into an `rgba()` at the given alpha — for the
|
|
145
|
-
* soft chip fills and translucent accents. Non-hex input passes through (so a
|
|
146
|
-
* caller may hand a hue that's already `rgba(...)`).
|
|
147
|
-
*/
|
|
148
|
-
export function withAlpha(hex: string, alpha: number): string {
|
|
149
|
-
const m = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.exec(hex)
|
|
150
|
-
if (!m) return hex
|
|
151
|
-
let h = m[1]
|
|
152
|
-
if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2]
|
|
153
|
-
const r = parseInt(h.slice(0, 2), 16)
|
|
154
|
-
const g = parseInt(h.slice(2, 4), 16)
|
|
155
|
-
const b = parseInt(h.slice(4, 6), 16)
|
|
156
|
-
const a = Math.max(0, Math.min(1, alpha))
|
|
157
|
-
return `rgba(${r}, ${g}, ${b}, ${a})`
|
|
158
|
-
}
|
package/src/cd/time.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compact relative time — pure and deterministic given `now`. Future or invalid
|
|
3
|
-
* timestamps degrade honestly (`—` / `now`), never a fabricated duration. Shared
|
|
4
|
-
* by the tile's last-synced, the drawer's created/age, and the history rows.
|
|
5
|
-
*/
|
|
6
|
-
export function relativeTime(
|
|
7
|
-
epochMs: number | undefined | null,
|
|
8
|
-
now: number = Date.now()
|
|
9
|
-
): string {
|
|
10
|
-
if (epochMs == null || !Number.isFinite(epochMs) || epochMs <= 0) return '—'
|
|
11
|
-
const diff = now - epochMs
|
|
12
|
-
if (diff < 0) return 'now'
|
|
13
|
-
const s = Math.floor(diff / 1000)
|
|
14
|
-
if (s < 5) return 'now'
|
|
15
|
-
if (s < 60) return `${s}s ago`
|
|
16
|
-
const m = Math.floor(s / 60)
|
|
17
|
-
if (m < 60) return `${m}m ago`
|
|
18
|
-
const h = Math.floor(m / 60)
|
|
19
|
-
if (h < 24) return `${h}h ago`
|
|
20
|
-
const d = Math.floor(h / 24)
|
|
21
|
-
if (d < 7) return `${d}d ago`
|
|
22
|
-
const w = Math.floor(d / 7)
|
|
23
|
-
if (w < 5) return `${w}w ago`
|
|
24
|
-
const mo = Math.floor(d / 30)
|
|
25
|
-
if (mo < 12) return `${mo}mo ago`
|
|
26
|
-
const y = Math.floor(d / 365)
|
|
27
|
-
return `${y}y ago`
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Parse an ISO-8601 (or any `Date`-parseable) timestamp to epoch **ms**, or
|
|
32
|
-
* `undefined` when absent/unparseable — so the contract's string timestamps
|
|
33
|
-
* (`createdAt`, event times) flow into `relativeTime` without throwing.
|
|
34
|
-
*/
|
|
35
|
-
export function toEpochMs(v: string | number | undefined | null): number | undefined {
|
|
36
|
-
if (v == null) return undefined
|
|
37
|
-
if (typeof v === 'number') {
|
|
38
|
-
if (!Number.isFinite(v) || v <= 0) return undefined
|
|
39
|
-
// Hanzo `/v1` rows may report epoch seconds; scale sub-2001 values to ms.
|
|
40
|
-
return v < 1e12 ? Math.round(v * 1000) : Math.round(v)
|
|
41
|
-
}
|
|
42
|
-
const t = Date.parse(v)
|
|
43
|
-
return Number.isFinite(t) && t > 0 ? t : undefined
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Relative time for a string/number timestamp (parses, then formats). */
|
|
47
|
-
export function relativeTimeOf(
|
|
48
|
-
v: string | number | undefined | null,
|
|
49
|
-
now: number = Date.now()
|
|
50
|
-
): string {
|
|
51
|
-
return relativeTime(toEpochMs(v), now)
|
|
52
|
-
}
|