@openshift-migration-advisor/shared-components 0.27.0-6438cd962b5f → 0.27.0-ad43dbdf05ab
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/report/ClustersOverview.d.ts +24 -0
- package/dist/report/ClustersOverview.d.ts.map +1 -0
- package/dist/report/ClustersOverview.js +228 -0
- package/dist/report/ClustersOverviewStyles.d.ts +12 -0
- package/dist/report/ClustersOverviewStyles.d.ts.map +1 -0
- package/dist/report/ClustersOverviewStyles.js +101 -0
- package/dist/report/CpuAndMemoryOverview.d.ts +19 -0
- package/dist/report/CpuAndMemoryOverview.d.ts.map +1 -0
- package/dist/report/CpuAndMemoryOverview.js +112 -0
- package/dist/report/captureChartElement.d.ts.map +1 -1
- package/dist/report/captureChartElement.js +28 -8
- package/dist/report/chartExport.d.ts +7 -0
- package/dist/report/chartExport.d.ts.map +1 -1
- package/dist/report/chartExport.js +20 -0
- package/dist/report/index.d.ts +2 -0
- package/dist/report/index.d.ts.map +1 -1
- package/dist/report/index.js +2 -0
- package/package.json +2 -2
- package/src/report/ClustersOverview.tsx +451 -0
- package/src/report/ClustersOverviewStyles.ts +110 -0
- package/src/report/CpuAndMemoryOverview.tsx +277 -0
- package/src/report/__tests__/ChartExportProvider.test.tsx +40 -0
- package/src/report/__tests__/ClustersOverview.test.tsx +241 -0
- package/src/report/__tests__/CpuAndMemoryOverview.test.tsx +200 -0
- package/src/report/__tests__/captureChartElement.test.ts +73 -0
- package/src/report/__tests__/chartExportPackagers.test.ts +17 -0
- package/src/report/captureChartElement.ts +37 -7
- package/src/report/chartExport.ts +22 -0
- package/src/report/index.ts +9 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import type { MigrationDonutChartProps } from "../../charts/MigrationDonutChart.js";
|
|
6
|
+
import { CpuAndMemoryOverview } from "../CpuAndMemoryOverview.js";
|
|
7
|
+
|
|
8
|
+
const donutProps = vi.hoisted(() => ({
|
|
9
|
+
current: null as MigrationDonutChartProps | null,
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock("../../charts/MigrationDonutChart.js", () => ({
|
|
13
|
+
MigrationDonutChart: (props: MigrationDonutChartProps): JSX.Element => {
|
|
14
|
+
donutProps.current = props;
|
|
15
|
+
return (
|
|
16
|
+
<div data-testid="cpu-memory-donut">
|
|
17
|
+
{props.title} {props.subTitle}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
donutProps.current = null;
|
|
25
|
+
cleanup();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const renderedDonut = (): MigrationDonutChartProps => {
|
|
29
|
+
const props = donutProps.current;
|
|
30
|
+
if (!props) {
|
|
31
|
+
throw new Error("expected a CPU and memory donut to render");
|
|
32
|
+
}
|
|
33
|
+
return props;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
describe("CpuAndMemoryOverview", () => {
|
|
37
|
+
it("shows the memory empty state when no memory tiers were collected", () => {
|
|
38
|
+
render(<CpuAndMemoryOverview />);
|
|
39
|
+
|
|
40
|
+
expect(screen.getByText("CPU & memory")).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByText("Memory size tiers")).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByText("Memory data not collected")).toBeInTheDocument();
|
|
43
|
+
expect(screen.queryByTestId("cpu-memory-donut")).not.toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("plots memory tiers from a plain count map and appends GB", () => {
|
|
47
|
+
render(
|
|
48
|
+
<CpuAndMemoryOverview
|
|
49
|
+
memoryTierDistribution={{
|
|
50
|
+
"129-256": 1,
|
|
51
|
+
"0-4": 2,
|
|
52
|
+
"256+": 3,
|
|
53
|
+
"5-16 GB": 4,
|
|
54
|
+
"17–32": 5,
|
|
55
|
+
unused: 0,
|
|
56
|
+
}}
|
|
57
|
+
memoryTotalGB={1024}
|
|
58
|
+
/>,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const props = renderedDonut();
|
|
62
|
+
expect(props.title).toBe("15 VMs");
|
|
63
|
+
expect(props.subTitle).toBe(`${(1024).toLocaleString()} GB`);
|
|
64
|
+
expect(props.data.map((slice) => [slice.name, slice.count])).toEqual([
|
|
65
|
+
["0-4 GB", 2],
|
|
66
|
+
["5-16 GB", 4],
|
|
67
|
+
["17–32 GB", 5],
|
|
68
|
+
["129-256 GB", 1],
|
|
69
|
+
["256+ GB", 3],
|
|
70
|
+
]);
|
|
71
|
+
expect(props.data.map((slice) => slice.legendCategory)).toEqual([
|
|
72
|
+
"0-4",
|
|
73
|
+
"5-16 GB",
|
|
74
|
+
"17–32",
|
|
75
|
+
"129-256",
|
|
76
|
+
"256+",
|
|
77
|
+
]);
|
|
78
|
+
expect(props.legend).toEqual({
|
|
79
|
+
"0-4": "#0066cc",
|
|
80
|
+
"5-16 GB": "#5e40be",
|
|
81
|
+
"17–32": "#b6a6e9",
|
|
82
|
+
"129-256": "#73c5c5",
|
|
83
|
+
"256+": "#b98412",
|
|
84
|
+
});
|
|
85
|
+
expect(props.legendVariant).toBe("html");
|
|
86
|
+
expect(props.marginLeft).toBeUndefined();
|
|
87
|
+
expect(props.onItemClick).toBeUndefined();
|
|
88
|
+
expect(props.onTitleClick).toBeUndefined();
|
|
89
|
+
expect(
|
|
90
|
+
props.legendLabelFormatter?.({ x: "0-4 GB", countDisplay: "2 VMs" }),
|
|
91
|
+
).toBe("0-4 GB (2 VMs)");
|
|
92
|
+
expect(
|
|
93
|
+
props.tooltipLabelFormatter?.({
|
|
94
|
+
datum: {
|
|
95
|
+
x: "0-4 GB",
|
|
96
|
+
y: 2,
|
|
97
|
+
countDisplay: "2 VMs",
|
|
98
|
+
legendCategory: "0-4",
|
|
99
|
+
},
|
|
100
|
+
percent: 13.333,
|
|
101
|
+
total: 15,
|
|
102
|
+
}),
|
|
103
|
+
).toBe("2 VMs\n13.3%");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("calls onTierSelect with the memory distribution key", () => {
|
|
107
|
+
const onTierSelect = vi.fn();
|
|
108
|
+
const onTitleClick = vi.fn();
|
|
109
|
+
render(
|
|
110
|
+
<CpuAndMemoryOverview
|
|
111
|
+
memoryTierDistribution={{ "0-4": 2 }}
|
|
112
|
+
onTierSelect={onTierSelect}
|
|
113
|
+
onTitleClick={onTitleClick}
|
|
114
|
+
/>,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
renderedDonut().onItemClick?.({
|
|
118
|
+
name: "0-4 GB",
|
|
119
|
+
count: 2,
|
|
120
|
+
legendCategory: "0-4",
|
|
121
|
+
});
|
|
122
|
+
renderedDonut().onTitleClick?.();
|
|
123
|
+
|
|
124
|
+
expect(onTierSelect).toHaveBeenCalledTimes(1);
|
|
125
|
+
expect(onTierSelect).toHaveBeenCalledWith("0-4");
|
|
126
|
+
expect(onTitleClick).toHaveBeenCalledTimes(1);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("switches to vCPU tiers and omits slice clicks", async () => {
|
|
130
|
+
const user = userEvent.setup();
|
|
131
|
+
const onTierSelect = vi.fn();
|
|
132
|
+
render(
|
|
133
|
+
<CpuAndMemoryOverview
|
|
134
|
+
legendVariant="chart"
|
|
135
|
+
cpuTierDistribution={{
|
|
136
|
+
"8": 1,
|
|
137
|
+
"2 cores": 2,
|
|
138
|
+
"1-2": 4,
|
|
139
|
+
"4+": 1,
|
|
140
|
+
idle: 0,
|
|
141
|
+
}}
|
|
142
|
+
cpuTotalCores={64}
|
|
143
|
+
memoryTierDistribution={{ "0-4": 2 }}
|
|
144
|
+
onTierSelect={onTierSelect}
|
|
145
|
+
/>,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
await user.click(
|
|
149
|
+
screen.getByRole("button", {
|
|
150
|
+
name: "VM distribution by memory size tier",
|
|
151
|
+
}),
|
|
152
|
+
);
|
|
153
|
+
await user.click(
|
|
154
|
+
screen.getByRole("menuitem", {
|
|
155
|
+
name: "VM distribution by vCPU count tier",
|
|
156
|
+
}),
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
expect(screen.getByText("vCPU count tiers")).toBeInTheDocument();
|
|
160
|
+
expect(
|
|
161
|
+
screen.getByRole("button", {
|
|
162
|
+
name: "VM distribution by vCPU count tier",
|
|
163
|
+
}),
|
|
164
|
+
).toBeInTheDocument();
|
|
165
|
+
|
|
166
|
+
const props = renderedDonut();
|
|
167
|
+
expect(props.title).toBe("8 VMs");
|
|
168
|
+
expect(props.subTitle).toBe(`${(64).toLocaleString()} Cores`);
|
|
169
|
+
expect(props.legendVariant).toBe("chart");
|
|
170
|
+
expect(props.marginLeft).toBe("52%");
|
|
171
|
+
expect(props.labelFontSize).toBe(18);
|
|
172
|
+
expect(props.itemsPerRow).toBe(2);
|
|
173
|
+
expect(props.data.map((slice) => [slice.name, slice.count])).toEqual([
|
|
174
|
+
["1-2 cores", 4],
|
|
175
|
+
["2 cores", 2],
|
|
176
|
+
["4+ cores", 1],
|
|
177
|
+
["8 cores", 1],
|
|
178
|
+
]);
|
|
179
|
+
expect(props.onItemClick).toBeUndefined();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("shows the CPU empty state when the selected distribution is empty", async () => {
|
|
183
|
+
const user = userEvent.setup();
|
|
184
|
+
render(<CpuAndMemoryOverview cpuTierDistribution={{}} />);
|
|
185
|
+
|
|
186
|
+
await user.click(
|
|
187
|
+
screen.getByRole("button", {
|
|
188
|
+
name: "VM distribution by memory size tier",
|
|
189
|
+
}),
|
|
190
|
+
);
|
|
191
|
+
await user.click(
|
|
192
|
+
screen.getByRole("menuitem", {
|
|
193
|
+
name: "VM distribution by vCPU count tier",
|
|
194
|
+
}),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
expect(screen.getByText("CPU data not collected")).toBeInTheDocument();
|
|
198
|
+
expect(screen.queryByTestId("cpu-memory-donut")).not.toBeInTheDocument();
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -16,6 +16,12 @@ const mockedHtml2Canvas = vi.mocked(html2canvas);
|
|
|
16
16
|
afterEach(() => {
|
|
17
17
|
mockedHtml2Canvas.mockClear();
|
|
18
18
|
document.body.replaceChildren();
|
|
19
|
+
document.documentElement.classList.remove(
|
|
20
|
+
"pf-v6-theme-dark",
|
|
21
|
+
"pf-v5-theme-dark",
|
|
22
|
+
);
|
|
23
|
+
document.documentElement.style.colorScheme = "";
|
|
24
|
+
document.body.style.colorScheme = "";
|
|
19
25
|
});
|
|
20
26
|
|
|
21
27
|
describe("captureChartElement", () => {
|
|
@@ -129,4 +135,71 @@ describe("captureChartElement", () => {
|
|
|
129
135
|
|
|
130
136
|
await captureChartElement(root);
|
|
131
137
|
});
|
|
138
|
+
|
|
139
|
+
it("applies light theme on the clone and leaves the live document dark", async () => {
|
|
140
|
+
document.documentElement.classList.add("pf-v6-theme-dark");
|
|
141
|
+
const root = document.createElement("div");
|
|
142
|
+
const card = document.createElement("div");
|
|
143
|
+
card.className = "pf-v6-c-card";
|
|
144
|
+
card.style.backgroundColor = "rgb(30, 30, 30)";
|
|
145
|
+
card.style.border = "1px solid rgb(80, 80, 80)";
|
|
146
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
147
|
+
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
148
|
+
text.style.fill = "rgb(255, 255, 255)";
|
|
149
|
+
text.textContent = "42";
|
|
150
|
+
svg.append(text);
|
|
151
|
+
card.append(svg);
|
|
152
|
+
root.append(card);
|
|
153
|
+
document.body.append(root);
|
|
154
|
+
|
|
155
|
+
mockedHtml2Canvas.mockImplementation(async (_element, options) => {
|
|
156
|
+
expect(
|
|
157
|
+
document.documentElement.classList.contains("pf-v6-theme-dark"),
|
|
158
|
+
).toBe(true);
|
|
159
|
+
|
|
160
|
+
const clonedDoc = document.implementation.createHTMLDocument("export");
|
|
161
|
+
clonedDoc.documentElement.classList.add("pf-v6-theme-dark");
|
|
162
|
+
const cloneRoot = clonedDoc.createElement("div");
|
|
163
|
+
const cloneCard = clonedDoc.createElement("div");
|
|
164
|
+
cloneCard.className = "pf-v6-c-card";
|
|
165
|
+
cloneCard.style.backgroundColor = "rgb(30, 30, 30)";
|
|
166
|
+
const cloneSvg = clonedDoc.createElementNS(
|
|
167
|
+
"http://www.w3.org/2000/svg",
|
|
168
|
+
"svg",
|
|
169
|
+
);
|
|
170
|
+
const cloneText = clonedDoc.createElementNS(
|
|
171
|
+
"http://www.w3.org/2000/svg",
|
|
172
|
+
"text",
|
|
173
|
+
);
|
|
174
|
+
cloneText.style.fill = "rgb(255, 255, 255)";
|
|
175
|
+
cloneSvg.append(cloneText);
|
|
176
|
+
cloneCard.append(cloneSvg);
|
|
177
|
+
cloneRoot.append(cloneCard);
|
|
178
|
+
clonedDoc.body.append(cloneRoot);
|
|
179
|
+
|
|
180
|
+
await options?.onclone?.(clonedDoc, cloneRoot);
|
|
181
|
+
|
|
182
|
+
expect(
|
|
183
|
+
clonedDoc.documentElement.classList.contains("pf-v6-theme-dark"),
|
|
184
|
+
).toBe(false);
|
|
185
|
+
expect(
|
|
186
|
+
document.documentElement.classList.contains("pf-v6-theme-dark"),
|
|
187
|
+
).toBe(true);
|
|
188
|
+
expect(cloneCard.style.backgroundColor).toBe("rgb(255, 255, 255)");
|
|
189
|
+
expect(cloneCard.style.borderColor).toBe("rgb(224, 224, 224)");
|
|
190
|
+
expect(cloneText.style.fill).toBe("rgb(21, 21, 21)");
|
|
191
|
+
|
|
192
|
+
const canvas = document.createElement("canvas");
|
|
193
|
+
canvas.width = 1;
|
|
194
|
+
canvas.height = 1;
|
|
195
|
+
return canvas;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await captureChartElement(root);
|
|
199
|
+
|
|
200
|
+
expect(
|
|
201
|
+
document.documentElement.classList.contains("pf-v6-theme-dark"),
|
|
202
|
+
).toBe(true);
|
|
203
|
+
expect(card.style.backgroundColor).toBe("rgb(30, 30, 30)");
|
|
204
|
+
});
|
|
132
205
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
|
+
applyLightThemeToDocument,
|
|
3
4
|
chartExportViewsFromLabels,
|
|
4
5
|
restoreChartExportViews,
|
|
5
6
|
sortRegisteredChartsByDocumentOrder,
|
|
@@ -280,3 +281,19 @@ describe("buildHtmlReport", () => {
|
|
|
280
281
|
expect(escapeHtml("it's")).toBe("it's");
|
|
281
282
|
});
|
|
282
283
|
});
|
|
284
|
+
|
|
285
|
+
describe("applyLightThemeToDocument", () => {
|
|
286
|
+
it("removes PatternFly dark theme classes from the given document", () => {
|
|
287
|
+
const clone = document.implementation.createHTMLDocument("export");
|
|
288
|
+
clone.documentElement.classList.add("pf-v6-theme-dark");
|
|
289
|
+
clone.body.style.colorScheme = "dark";
|
|
290
|
+
|
|
291
|
+
applyLightThemeToDocument(clone);
|
|
292
|
+
|
|
293
|
+
expect(clone.documentElement.classList.contains("pf-v6-theme-dark")).toBe(
|
|
294
|
+
false,
|
|
295
|
+
);
|
|
296
|
+
expect(clone.documentElement.style.colorScheme).toBe("light");
|
|
297
|
+
expect(clone.body.style.colorScheme).toBe("light");
|
|
298
|
+
});
|
|
299
|
+
});
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
t_color_gray_20,
|
|
3
|
+
t_color_white,
|
|
4
|
+
t_global_text_color_regular,
|
|
5
|
+
} from "@patternfly/react-tokens";
|
|
1
6
|
import html2canvas from "html2canvas-pro";
|
|
2
7
|
import {
|
|
8
|
+
applyLightThemeToDocument,
|
|
3
9
|
CHART_EXPORT_CAPTURING_ATTR,
|
|
4
10
|
CHART_EXPORT_SCROLL_ATTR,
|
|
5
11
|
shouldIgnoreChartExportElement,
|
|
@@ -94,6 +100,10 @@ const PADDED_CAPTURE_SELECTOR =
|
|
|
94
100
|
".pf-v6-c-card__title, .pf-v6-c-card__header, .pf-v6-c-card__body";
|
|
95
101
|
const CARD_CAPTURE_SELECTOR = ".pf-v6-c-card";
|
|
96
102
|
const TRANSPARENT_FILLS = new Set(["", "transparent", "rgba(0, 0, 0, 0)"]);
|
|
103
|
+
/** PatternFly light-theme chrome. html2canvas inlines live computed SVG styles. */
|
|
104
|
+
const LIGHT_EXPORT_BACKGROUND = t_color_white.value;
|
|
105
|
+
const LIGHT_EXPORT_BORDER = t_color_gray_20.value;
|
|
106
|
+
const LIGHT_EXPORT_TEXT = t_global_text_color_regular.value;
|
|
97
107
|
|
|
98
108
|
function queryCards(root: HTMLElement): HTMLElement[] {
|
|
99
109
|
const cards = Array.from(
|
|
@@ -149,16 +159,34 @@ function readCardBorder(source: HTMLElement): {
|
|
|
149
159
|
return { width, style, color };
|
|
150
160
|
}
|
|
151
161
|
|
|
152
|
-
function applyCardChrome(
|
|
162
|
+
function applyCardChrome(
|
|
163
|
+
source: HTMLElement,
|
|
164
|
+
dest: HTMLElement,
|
|
165
|
+
colors: "computed" | "light",
|
|
166
|
+
): void {
|
|
153
167
|
const computed = window.getComputedStyle(source);
|
|
154
168
|
dest.style.borderRadius = computed.borderRadius;
|
|
155
|
-
dest.style.backgroundColor = resolvedFill(computed.backgroundColor);
|
|
156
169
|
dest.style.overflow = "hidden";
|
|
170
|
+
dest.style.backgroundColor =
|
|
171
|
+
colors === "light"
|
|
172
|
+
? LIGHT_EXPORT_BACKGROUND
|
|
173
|
+
: resolvedFill(computed.backgroundColor);
|
|
157
174
|
const border = readCardBorder(source);
|
|
158
175
|
if (border) {
|
|
159
176
|
dest.style.borderWidth = border.width;
|
|
160
177
|
dest.style.borderStyle = border.style;
|
|
161
|
-
dest.style.borderColor =
|
|
178
|
+
dest.style.borderColor =
|
|
179
|
+
colors === "light" ? LIGHT_EXPORT_BORDER : border.color;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function applyLightThemeSvgText(root: HTMLElement): void {
|
|
184
|
+
for (const node of root.querySelectorAll("text, tspan")) {
|
|
185
|
+
if (!(node instanceof SVGElement)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
node.style.fill = LIGHT_EXPORT_TEXT;
|
|
189
|
+
node.style.color = LIGHT_EXPORT_TEXT;
|
|
162
190
|
}
|
|
163
191
|
}
|
|
164
192
|
|
|
@@ -218,7 +246,7 @@ function copyCardChrome(node: HTMLElement): {
|
|
|
218
246
|
height: node.style.height,
|
|
219
247
|
maxHeight: node.style.maxHeight,
|
|
220
248
|
};
|
|
221
|
-
applyCardChrome(node, node);
|
|
249
|
+
applyCardChrome(node, node, "computed");
|
|
222
250
|
node.style.minHeight = "0px";
|
|
223
251
|
node.style.height = "auto";
|
|
224
252
|
node.style.maxHeight = "none";
|
|
@@ -234,7 +262,7 @@ function applyComputedStylesToClone(
|
|
|
234
262
|
sourceCards.forEach((source, index) => {
|
|
235
263
|
const dest = cloneCards[index];
|
|
236
264
|
if (dest) {
|
|
237
|
-
applyCardChrome(source, dest);
|
|
265
|
+
applyCardChrome(source, dest, "light");
|
|
238
266
|
}
|
|
239
267
|
});
|
|
240
268
|
|
|
@@ -348,15 +376,17 @@ export async function captureChartElement(
|
|
|
348
376
|
}
|
|
349
377
|
return html2canvas(element, {
|
|
350
378
|
useCORS: true,
|
|
351
|
-
backgroundColor:
|
|
379
|
+
backgroundColor: LIGHT_EXPORT_BACKGROUND,
|
|
352
380
|
logging: false,
|
|
353
381
|
scale: CHART_CAPTURE_SCALE,
|
|
354
382
|
imageTimeout: 0,
|
|
355
383
|
ignoreElements: (node) =>
|
|
356
384
|
node instanceof Element &&
|
|
357
385
|
shouldIgnoreChartExportElement(node, element),
|
|
358
|
-
onclone: (
|
|
386
|
+
onclone: (clonedDoc, clonedElement) => {
|
|
387
|
+
applyLightThemeToDocument(clonedDoc);
|
|
359
388
|
applyComputedStylesToClone(element, clonedElement);
|
|
389
|
+
applyLightThemeSvgText(clonedElement);
|
|
360
390
|
},
|
|
361
391
|
});
|
|
362
392
|
} finally {
|
|
@@ -85,6 +85,28 @@ export function waitForChartExportPaint(): Promise<void> {
|
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/** PatternFly applies dark tokens when this class is on `:root`. */
|
|
89
|
+
export const PATTERNFLY_DARK_THEME_CLASSES = [
|
|
90
|
+
"pf-v6-theme-dark",
|
|
91
|
+
"pf-v5-theme-dark",
|
|
92
|
+
] as const;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Force PatternFly light tokens on a document (the html2canvas clone).
|
|
96
|
+
* Does not touch the live page.
|
|
97
|
+
*/
|
|
98
|
+
export function applyLightThemeToDocument(root: Document): void {
|
|
99
|
+
for (const node of [root.documentElement, root.body]) {
|
|
100
|
+
if (!node) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
for (const className of PATTERNFLY_DARK_THEME_CLASSES) {
|
|
104
|
+
node.classList.remove(className);
|
|
105
|
+
}
|
|
106
|
+
node.style.colorScheme = "light";
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
88
110
|
export function chartExportViewsFromLabels(
|
|
89
111
|
titlePrefix: string,
|
|
90
112
|
labels: Record<string, string>,
|
package/src/report/index.ts
CHANGED
|
@@ -17,6 +17,15 @@ export {
|
|
|
17
17
|
type ZipChartFiles,
|
|
18
18
|
} from "./ChartExportProvider.js";
|
|
19
19
|
export { ChartExportSurface } from "./ChartExportSurface.js";
|
|
20
|
+
export {
|
|
21
|
+
ClustersOverview,
|
|
22
|
+
type ClustersOverviewProps,
|
|
23
|
+
type InventoryDataLike,
|
|
24
|
+
} from "./ClustersOverview.js";
|
|
25
|
+
export {
|
|
26
|
+
CpuAndMemoryOverview,
|
|
27
|
+
type CpuAndMemoryOverviewProps,
|
|
28
|
+
} from "./CpuAndMemoryOverview.js";
|
|
20
29
|
export { captureChartElement } from "./captureChartElement.js";
|
|
21
30
|
export {
|
|
22
31
|
CHART_EXPORT_CAPTURING_ATTR,
|