@wopr-network/platform-ui-core 1.1.2 → 1.1.4
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,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wopr-network/platform-ui-core",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Brand-agnostic AI agent platform UI — deploy as any brand via env vars",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/wopr-network/platform-ui-core.git"
|
|
8
8
|
},
|
|
9
9
|
"license": "UNLICENSED",
|
|
10
|
+
"packageManager": "pnpm@10.31.0",
|
|
10
11
|
"exports": {
|
|
11
12
|
".": "./src/lib/index.ts",
|
|
12
13
|
"./app/*": "./src/app/*",
|
|
@@ -31,6 +32,16 @@
|
|
|
31
32
|
"vitest.config.ts",
|
|
32
33
|
".env.wopr"
|
|
33
34
|
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"dev": "next dev",
|
|
37
|
+
"build": "next build",
|
|
38
|
+
"start": "next start",
|
|
39
|
+
"lint": "biome check src/",
|
|
40
|
+
"format": "biome format --write src/",
|
|
41
|
+
"check": "biome check src/ && tsc --noEmit",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:e2e": "playwright test"
|
|
44
|
+
},
|
|
34
45
|
"dependencies": {
|
|
35
46
|
"@hookform/resolvers": "^5.2.2",
|
|
36
47
|
"@stripe/react-stripe-js": "^5.6.0",
|
|
@@ -79,14 +90,7 @@
|
|
|
79
90
|
"typescript": "^5",
|
|
80
91
|
"vitest": "^4.0.18"
|
|
81
92
|
},
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"build": "next build",
|
|
85
|
-
"start": "next start",
|
|
86
|
-
"lint": "biome check src/",
|
|
87
|
-
"format": "biome format --write src/",
|
|
88
|
-
"check": "biome check src/ && tsc --noEmit",
|
|
89
|
-
"test": "vitest run",
|
|
90
|
-
"test:e2e": "playwright test"
|
|
93
|
+
"release": {
|
|
94
|
+
"extends": "@wopr-network/semantic-release-config"
|
|
91
95
|
}
|
|
92
|
-
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
describe("buy-credits-panel logger usage", () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
vi.resetModules();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("should use logger instead of raw console.error", async () => {
|
|
9
|
+
const fs = await import("node:fs");
|
|
10
|
+
const source = fs.readFileSync("src/components/billing/buy-credits-panel.tsx", "utf-8");
|
|
11
|
+
|
|
12
|
+
// Must import logger
|
|
13
|
+
expect(source).toContain('import { logger } from "@/lib/logger"');
|
|
14
|
+
|
|
15
|
+
// Must NOT have raw console.error
|
|
16
|
+
expect(source).not.toMatch(/console\.error\(/);
|
|
17
|
+
|
|
18
|
+
// Must use log.error
|
|
19
|
+
expect(source).toMatch(/log\.error\(/);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -90,7 +90,7 @@ describe("GpuDashboard", () => {
|
|
|
90
90
|
mockListGpuNodes.mockResolvedValue([]);
|
|
91
91
|
render(<GpuDashboard />);
|
|
92
92
|
await waitFor(() => {
|
|
93
|
-
expect(screen.getByText(/GPU Management/i)).
|
|
93
|
+
expect(screen.getByText(/GPU Management/i)).toBeInTheDocument();
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
96
|
|
|
@@ -98,10 +98,10 @@ describe("GpuDashboard", () => {
|
|
|
98
98
|
mockListGpuNodes.mockResolvedValue([fakeNode({ name: "my-gpu" })]);
|
|
99
99
|
render(<GpuDashboard />);
|
|
100
100
|
await waitFor(() => {
|
|
101
|
-
expect(screen.getByText("my-gpu")).
|
|
101
|
+
expect(screen.getByText("my-gpu")).toBeInTheDocument();
|
|
102
102
|
});
|
|
103
|
-
expect(screen.getByText("running")).
|
|
104
|
-
expect(screen.getByText("42%")).
|
|
103
|
+
expect(screen.getByText("running")).toBeInTheDocument();
|
|
104
|
+
expect(screen.getByText("42%")).toBeInTheDocument();
|
|
105
105
|
// Temperature appears in both the KPI card and the table row
|
|
106
106
|
expect(screen.getAllByText("65°C").length).toBeGreaterThan(0);
|
|
107
107
|
});
|
|
@@ -110,7 +110,7 @@ describe("GpuDashboard", () => {
|
|
|
110
110
|
mockListGpuNodes.mockResolvedValue([]);
|
|
111
111
|
render(<GpuDashboard />);
|
|
112
112
|
await waitFor(() => {
|
|
113
|
-
expect(screen.getByText(/No GPU nodes provisioned/i)).
|
|
113
|
+
expect(screen.getByText(/No GPU nodes provisioned/i)).toBeInTheDocument();
|
|
114
114
|
});
|
|
115
115
|
});
|
|
116
116
|
|
|
@@ -118,7 +118,7 @@ describe("GpuDashboard", () => {
|
|
|
118
118
|
mockListGpuNodes.mockRejectedValue(new Error("API down"));
|
|
119
119
|
render(<GpuDashboard />);
|
|
120
120
|
await waitFor(() => {
|
|
121
|
-
expect(screen.getByText("API down")).
|
|
121
|
+
expect(screen.getByText("API down")).toBeInTheDocument();
|
|
122
122
|
});
|
|
123
123
|
});
|
|
124
124
|
|
|
@@ -130,8 +130,8 @@ describe("GpuDashboard", () => {
|
|
|
130
130
|
render(<GpuDashboard />);
|
|
131
131
|
await waitFor(() => {
|
|
132
132
|
// Total nodes = 2, Running = 1
|
|
133
|
-
expect(screen.getByText("Total Nodes")).
|
|
134
|
-
expect(screen.getByText("Running")).
|
|
133
|
+
expect(screen.getByText("Total Nodes")).toBeInTheDocument();
|
|
134
|
+
expect(screen.getByText("Running")).toBeInTheDocument();
|
|
135
135
|
});
|
|
136
136
|
});
|
|
137
137
|
|
|
@@ -139,8 +139,8 @@ describe("GpuDashboard", () => {
|
|
|
139
139
|
mockListGpuNodes.mockResolvedValue([]);
|
|
140
140
|
render(<GpuDashboard />);
|
|
141
141
|
await waitFor(() => {
|
|
142
|
-
expect(screen.getByText(/Allocation \/ Tenant Mapping/i)).
|
|
143
|
-
expect(screen.getByText(/GPU Configuration/i)).
|
|
142
|
+
expect(screen.getByText(/Allocation \/ Tenant Mapping/i)).toBeInTheDocument();
|
|
143
|
+
expect(screen.getByText(/GPU Configuration/i)).toBeInTheDocument();
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
146
|
|
|
@@ -206,7 +206,7 @@ describe("GpuDashboard", () => {
|
|
|
206
206
|
|
|
207
207
|
await userEvent.click(screen.getByText(/Provision Node/i));
|
|
208
208
|
|
|
209
|
-
expect(screen.getByText(/Provision New GPU Node/i)).
|
|
209
|
+
expect(screen.getByText(/Provision New GPU Node/i)).toBeInTheDocument();
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
it("submits provision form and adds new node", async () => {
|
|
@@ -61,14 +61,14 @@ describe("NetworkPage", () => {
|
|
|
61
61
|
it("renders page heading", async () => {
|
|
62
62
|
vi.mocked(listInstances).mockResolvedValue(MOCK_INSTANCES);
|
|
63
63
|
render(<NetworkPage />);
|
|
64
|
-
expect(screen.getByText(/friends/i)).
|
|
64
|
+
expect(screen.getByText(/friends/i)).toBeInTheDocument();
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it("shows instance selector after load", async () => {
|
|
68
68
|
vi.mocked(listInstances).mockResolvedValue(MOCK_INSTANCES);
|
|
69
69
|
render(<NetworkPage />);
|
|
70
70
|
await waitFor(() => {
|
|
71
|
-
expect(screen.getByRole("combobox", { name: /select instance/i })).
|
|
71
|
+
expect(screen.getByRole("combobox", { name: /select instance/i })).toBeInTheDocument();
|
|
72
72
|
});
|
|
73
73
|
});
|
|
74
74
|
|
|
@@ -76,7 +76,7 @@ describe("NetworkPage", () => {
|
|
|
76
76
|
vi.mocked(listInstances).mockResolvedValue(MOCK_INSTANCES);
|
|
77
77
|
render(<NetworkPage />);
|
|
78
78
|
await waitFor(() => {
|
|
79
|
-
expect(screen.getByText(/select an instance to manage friends/i)).
|
|
79
|
+
expect(screen.getByText(/select an instance to manage friends/i)).toBeInTheDocument();
|
|
80
80
|
});
|
|
81
81
|
});
|
|
82
82
|
|
|
@@ -94,7 +94,7 @@ describe("NetworkPage", () => {
|
|
|
94
94
|
vi.mocked(listInstances).mockRejectedValue(new Error("network error"));
|
|
95
95
|
render(<NetworkPage />);
|
|
96
96
|
await waitFor(() => {
|
|
97
|
-
expect(screen.getByText(/network error/i)).
|
|
97
|
+
expect(screen.getByText(/network error/i)).toBeInTheDocument();
|
|
98
98
|
});
|
|
99
99
|
});
|
|
100
100
|
});
|
|
@@ -8,9 +8,12 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
|
8
8
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
9
9
|
import type { CreditOption } from "@/lib/api";
|
|
10
10
|
import { createCreditCheckout, getCreditOptions } from "@/lib/api";
|
|
11
|
+
import { logger } from "@/lib/logger";
|
|
11
12
|
import { cn } from "@/lib/utils";
|
|
12
13
|
import { isAllowedRedirectUrl } from "@/lib/validate-redirect-url";
|
|
13
14
|
|
|
15
|
+
const log = logger("billing:buy-credits");
|
|
16
|
+
|
|
14
17
|
export function BuyCreditsPanel() {
|
|
15
18
|
const [tiers, setTiers] = useState<CreditOption[]>([]);
|
|
16
19
|
const [tiersLoading, setTiersLoading] = useState(true);
|
|
@@ -28,7 +31,7 @@ export function BuyCreditsPanel() {
|
|
|
28
31
|
setTiersLoading(false);
|
|
29
32
|
})
|
|
30
33
|
.catch((err) => {
|
|
31
|
-
|
|
34
|
+
log.error("Failed to load credit options:", err);
|
|
32
35
|
setLoadError(true);
|
|
33
36
|
setTiersLoading(false);
|
|
34
37
|
});
|
|
@@ -47,7 +50,7 @@ export function BuyCreditsPanel() {
|
|
|
47
50
|
})
|
|
48
51
|
.catch((err) => {
|
|
49
52
|
if (!cancelled) {
|
|
50
|
-
|
|
53
|
+
log.error("Failed to load credit options:", err);
|
|
51
54
|
setLoadError(true);
|
|
52
55
|
setTiersLoading(false);
|
|
53
56
|
}
|