@umituz/web-dashboard 6.2.1 → 6.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-dashboard",
3
- "version": "6.2.1",
3
+ "version": "6.4.0",
4
4
  "description": "Installable app skeleton for the fleet — layouts, analytics (dependency-free SVG charts), calendar, onboarding flow, i18n via @umituz/web-localization, permissions/module registry; udb-* stylesheet on design-system tokens",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -10,35 +10,36 @@
10
10
  ],
11
11
  "exports": {
12
12
  ".": "./src/index.ts",
13
- "./styles.css": "./src/styles/dashboard.css",
14
- "./permissions": "./src/domains/permissions/index.ts",
15
- "./modules": "./src/domains/modules/index.ts",
16
- "./layouts": "./src/domains/layouts/index.ts",
17
- "./layouts/components": "./src/domains/layouts/components/index.ts",
18
- "./layouts/hooks": "./src/domains/layouts/hooks/index.ts",
19
- "./layouts/utils": "./src/domains/layouts/utils/index.ts",
20
- "./layouts/types": "./src/domains/layouts/types/index.ts",
21
- "./layouts/theme": "./src/domains/layouts/theme/index.ts",
22
- "./settings": "./src/domains/settings/index.ts",
23
- "./settings/components": "./src/domains/settings/components/index.ts",
24
- "./settings/hooks": "./src/domains/settings/hooks/index.ts",
25
- "./settings/utils": "./src/domains/settings/utils/index.ts",
26
- "./settings/types": "./src/domains/settings/types/index.ts",
27
13
  "./analytics": "./src/domains/analytics/index.ts",
28
14
  "./analytics/components": "./src/domains/analytics/components/index.ts",
29
15
  "./analytics/hooks": "./src/domains/analytics/hooks/index.ts",
30
- "./analytics/utils": "./src/domains/analytics/utils/index.ts",
31
- "./analytics/types": "./src/domains/analytics/types/index.ts",
32
16
  "./analytics/services": "./src/domains/analytics/services/index.ts",
17
+ "./analytics/types": "./src/domains/analytics/types/index.ts",
18
+ "./analytics/utils": "./src/domains/analytics/utils/index.ts",
33
19
  "./calendar": "./src/domains/calendar/index.ts",
34
- "./calendar/types": "./src/domains/calendar/types/calendar.types.ts",
35
- "./calendar/services": "./src/domains/calendar/services/index.ts",
36
20
  "./calendar/hooks": "./src/domains/calendar/hooks/index.ts",
21
+ "./calendar/services": "./src/domains/calendar/services/index.ts",
22
+ "./calendar/types": "./src/domains/calendar/types/calendar.types.ts",
37
23
  "./calendar/utils": "./src/domains/calendar/utils/index.ts",
24
+ "./charts": "./src/domains/charts/index.ts",
25
+ "./chrome.css": "./src/styles/chrome.css",
38
26
  "./config": "./src/config/index.ts",
27
+ "./layouts": "./src/domains/layouts/index.ts",
28
+ "./layouts/components": "./src/domains/layouts/components/index.ts",
29
+ "./layouts/hooks": "./src/domains/layouts/hooks/index.ts",
30
+ "./layouts/theme": "./src/domains/layouts/theme/index.ts",
31
+ "./layouts/types": "./src/domains/layouts/types/index.ts",
32
+ "./layouts/utils": "./src/domains/layouts/utils/index.ts",
33
+ "./modules": "./src/domains/modules/index.ts",
34
+ "./onboarding": "./src/domains/onboarding/index.ts",
39
35
  "./package.json": "./package.json",
40
- "./charts": "./src/domains/charts/index.ts",
41
- "./onboarding": "./src/domains/onboarding/index.ts"
36
+ "./permissions": "./src/domains/permissions/index.ts",
37
+ "./settings": "./src/domains/settings/index.ts",
38
+ "./settings/components": "./src/domains/settings/components/index.ts",
39
+ "./settings/hooks": "./src/domains/settings/hooks/index.ts",
40
+ "./settings/types": "./src/domains/settings/types/index.ts",
41
+ "./settings/utils": "./src/domains/settings/utils/index.ts",
42
+ "./styles.css": "./src/styles/dashboard.css"
42
43
  },
43
44
  "files": [
44
45
  "src",
@@ -86,6 +86,29 @@ describe('charts markup smoke', () => {
86
86
  expect(html).toContain('height:100%');
87
87
  });
88
88
 
89
+ it('BarChart renders a dashed goal line that counts toward max and clamps at 100%', () => {
90
+ const html = renderToString(
91
+ <BarChart
92
+ labels={['a', 'b']}
93
+ series={[{ label: 'A', values: [2, 4] }]}
94
+ goalLine={{ value: 4, label: 'goal 4', tone: '#111111' }}
95
+ />,
96
+ );
97
+ expect(html).toContain('udb-barchart__goal');
98
+ expect(html).toContain('bottom:100%');
99
+ expect(html).toContain('border-top-color:#111111');
100
+ expect(html).toContain('>goal 4<');
101
+
102
+ const above = renderToString(
103
+ <BarChart labels={['a']} series={[{ label: 'A', values: [2] }]} goalLine={{ value: 99 }} />,
104
+ );
105
+ expect(above).toContain('bottom:100%');
106
+ expect(above).not.toContain('udb-barchart__goallabel');
107
+
108
+ const without = renderToString(<BarChart labels={['a']} series={[{ label: 'A', values: [2] }]} />);
109
+ expect(without).not.toContain('udb-barchart__goal');
110
+ });
111
+
89
112
  it('fleet aliases: Legend renders hint suffix and Donut accepts color', () => {
90
113
  const html = renderToString(
91
114
  <>
@@ -149,25 +149,58 @@ export interface BarSeries {
149
149
  color?: string;
150
150
  }
151
151
 
152
+ export interface BarChartGoalLine {
153
+ value: number;
154
+ label?: string;
155
+ tone?: string;
156
+ }
157
+
152
158
  export function BarChart({
153
159
  labels,
154
160
  series,
155
161
  height = 130,
156
162
  formatValue = (v: number) => String(v),
157
163
  formatLabel = (l: string) => l,
164
+ goalLine,
158
165
  }: {
159
166
  labels: readonly string[];
160
167
  series: BarSeries[];
161
168
  height?: number;
162
169
  formatValue?: (v: number) => string;
163
170
  formatLabel?: (l: string) => string;
171
+ goalLine?: BarChartGoalLine;
164
172
  }) {
165
173
  const [hover, setHover] = useState<number | null>(null);
166
174
  const vals = (s: BarSeries) => s.values ?? s.data ?? [];
167
- const max = Math.max(1, ...series.flatMap((s) => vals(s)));
175
+ const max = Math.max(1, ...series.flatMap((s) => vals(s)), goalLine?.value ?? 0);
168
176
  const toneOf = (s: BarSeries, i: number) => s.tone ?? s.color ?? PALETTE[i % PALETTE.length]!;
177
+ const goalPct = goalLine !== undefined ? Math.min(100, (goalLine.value / max) * 100) : null;
169
178
  return (
170
179
  <div className="udb-barchart" style={{ height }}>
180
+ {goalLine !== undefined && goalPct !== null && (
181
+ <div
182
+ className="udb-barchart__goal"
183
+ style={{
184
+ bottom: `${goalPct}%`,
185
+ ...(goalLine.tone !== undefined ? { borderTopColor: goalLine.tone } : {}),
186
+ }}
187
+ title={goalLine.label ?? formatValue(goalLine.value)}
188
+ aria-hidden="true"
189
+ >
190
+ {goalLine.label !== undefined && (
191
+ <span
192
+ className="udb-barchart__goallabel"
193
+ style={
194
+ goalLine.tone !== undefined
195
+ ? { color: goalLine.tone, borderColor: goalLine.tone }
196
+ : undefined
197
+ }
198
+ >
199
+ {goalLine.label}
200
+ </span>
201
+ )}
202
+ </div>
203
+ )}
171
204
  {labels.map((label, i) => (
172
205
  <div
173
206
  key={label}