create-bluecopa-react-app 1.0.11 → 1.0.13
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/bin/create-bluecopa-react-app.js +1 -1
- package/package.json +1 -1
- package/templates/latest/.dockerignore +5 -1
- package/templates/latest/Agent.md +621 -0
- package/templates/latest/Dockerfile +2 -2
- package/templates/latest/app/app.tsx +3 -1
- package/templates/latest/app/components/app-sidebar.tsx +14 -16
- package/templates/latest/app/components/nav-main.tsx +6 -22
- package/templates/latest/app/data/mock-payments.json +122 -0
- package/templates/latest/app/data/mock-transactions.json +128 -0
- package/templates/latest/app/routes/comments.tsx +552 -0
- package/templates/latest/app/routes/{home.tsx → dashboard.tsx} +1 -1
- package/templates/latest/app/routes/payments.tsx +342 -0
- package/templates/latest/app/routes/websocket.tsx +450 -0
- package/templates/latest/app/routes.tsx +8 -5
- package/templates/latest/dist/assets/{__federation_expose_App-C8_sl1dD.js → __federation_expose_App-BIH7hwj_.js} +12 -2
- package/templates/latest/dist/assets/{home-DhyEFlEc.js → client-CsvW46cT.js} +18530 -983
- package/templates/latest/dist/assets/{index-DkyIpbj3.js → index-CFECuPSy.js} +1 -1
- package/templates/latest/dist/assets/remoteEntry.css +155 -23
- package/templates/latest/dist/assets/remoteEntry.js +1 -1
- package/templates/latest/dist/favicon.ico +0 -0
- package/templates/latest/dist/index.html +2 -2
- package/templates/latest/package-lock.json +203 -203
- package/templates/latest/package.json +1 -1
- package/templates/latest/public/favicon.ico +0 -0
- package/templates/latest/dist/assets/client-Hh38T4k9.js +0 -12660
- package/templates/latest/dist/avatars/shadcn.svg +0 -6
- package/templates/latest/public/avatars/shadcn.svg +0 -6
- /package/templates/latest/app/{dashboard → data}/data.json +0 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { AppSidebar } from "~/components/app-sidebar";
|
|
3
|
+
import { SiteHeader } from "~/components/site-header";
|
|
4
|
+
import { SidebarInset, SidebarProvider } from "~/components/ui/sidebar";
|
|
5
|
+
import { Button } from "~/components/ui/button";
|
|
6
|
+
import { Input } from "~/components/ui/input";
|
|
7
|
+
import { Label } from "~/components/ui/label";
|
|
8
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
|
|
9
|
+
import { Separator } from "~/components/ui/separator";
|
|
10
|
+
import { Badge } from "~/components/ui/badge";
|
|
11
|
+
import { copaUtils, copaGetConfig } from "@bluecopa/react";
|
|
12
|
+
|
|
13
|
+
interface WebSocketEvent {
|
|
14
|
+
id: string;
|
|
15
|
+
timestamp: Date;
|
|
16
|
+
channel: string;
|
|
17
|
+
event: string;
|
|
18
|
+
data: any;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function WebsocketTestPage() {
|
|
22
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
23
|
+
const [connectionUrl, setConnectionUrl] = useState("");
|
|
24
|
+
const [channel, setChannel] = useState("test-channel");
|
|
25
|
+
const [eventName, setEventName] = useState("message");
|
|
26
|
+
const [events, setEvents] = useState<WebSocketEvent[]>([]);
|
|
27
|
+
const [subscriptions, setSubscriptions] = useState<Set<string>>(new Set());
|
|
28
|
+
const wsProviderRef = useRef<any | null>(null);
|
|
29
|
+
|
|
30
|
+
// Cleanup on unmount
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
return () => {
|
|
33
|
+
if (wsProviderRef && wsProviderRef.current) {
|
|
34
|
+
wsProviderRef.current.disconnect();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const handleConnect = () => {
|
|
40
|
+
try {
|
|
41
|
+
// Get current config to use access token and userId
|
|
42
|
+
const config = copaGetConfig();
|
|
43
|
+
|
|
44
|
+
if (!config.accessToken || !config.userId) {
|
|
45
|
+
addEvent("system", "error", {
|
|
46
|
+
error: "Missing configuration. Ensure accessToken and userId are set via copaSetConfig()"
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Create websocket provider using the factory
|
|
52
|
+
wsProviderRef.current = copaUtils.websocketUtils.WebsocketContextFactory.create(
|
|
53
|
+
"centrifugo",
|
|
54
|
+
{
|
|
55
|
+
connectionUrl: connectionUrl,
|
|
56
|
+
token: config.accessToken,
|
|
57
|
+
userId: config.userId
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
setIsConnected(true);
|
|
62
|
+
addEvent("system", "connected", { url: connectionUrl || "default" });
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error("Failed to connect:", error);
|
|
65
|
+
addEvent("system", "error", { error: String(error) });
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const handleDisconnect = () => {
|
|
70
|
+
if (wsProviderRef.current) {
|
|
71
|
+
wsProviderRef.current.disconnect();
|
|
72
|
+
wsProviderRef.current = null;
|
|
73
|
+
setIsConnected(false);
|
|
74
|
+
setSubscriptions(new Set());
|
|
75
|
+
addEvent("system", "disconnected", {});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const handleSubscribe = () => {
|
|
80
|
+
if (!wsProviderRef.current || !isConnected) {
|
|
81
|
+
addEvent("system", "error", { error: "Not connected to websocket" });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const subscriptionKey = `${channel}#${eventName}`;
|
|
86
|
+
|
|
87
|
+
if (subscriptions.has(subscriptionKey)) {
|
|
88
|
+
addEvent("system", "warning", { warning: `Already subscribed to ${subscriptionKey}` });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
// Bind to a private channel (user-specific)
|
|
94
|
+
wsProviderRef.current.bind(channel, eventName, (data: any) => {
|
|
95
|
+
addEvent(channel, eventName, data);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
setSubscriptions(new Set([...subscriptions, subscriptionKey]));
|
|
99
|
+
addEvent("system", "subscribed", { channel, event: eventName });
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error("Failed to subscribe:", error);
|
|
102
|
+
addEvent("system", "error", { error: String(error) });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const handleSubscribeGlobal = () => {
|
|
107
|
+
if (!wsProviderRef.current || !isConnected) {
|
|
108
|
+
addEvent("system", "error", { error: "Not connected to websocket" });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const globalChannel = channel;
|
|
113
|
+
|
|
114
|
+
if (subscriptions.has(`global:${globalChannel}`)) {
|
|
115
|
+
addEvent("system", "warning", { warning: `Already subscribed to global channel ${globalChannel}` });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Bind to a global channel (not user-specific)
|
|
121
|
+
wsProviderRef.current.bindGlobal(globalChannel, (data: any) => {
|
|
122
|
+
addEvent(`global:${globalChannel}`, "publication", data);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
setSubscriptions(new Set([...subscriptions, `global:${globalChannel}`]));
|
|
126
|
+
addEvent("system", "subscribed", { channel: `global:${globalChannel}` });
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error("Failed to subscribe to global channel:", error);
|
|
129
|
+
addEvent("system", "error", { error: String(error) });
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const handleUnsubscribe = () => {
|
|
134
|
+
if (!wsProviderRef.current || !isConnected) {
|
|
135
|
+
addEvent("system", "error", { error: "Not connected to websocket" });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const subscriptionKey = `${channel}#${eventName}`;
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
wsProviderRef.current.unbind(channel, eventName);
|
|
143
|
+
const newSubscriptions = new Set(subscriptions);
|
|
144
|
+
newSubscriptions.delete(subscriptionKey);
|
|
145
|
+
setSubscriptions(newSubscriptions);
|
|
146
|
+
addEvent("system", "unsubscribed", { channel, event: eventName });
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error("Failed to unsubscribe:", error);
|
|
149
|
+
addEvent("system", "error", { error: String(error) });
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const handleUnsubscribeAll = () => {
|
|
154
|
+
if (!wsProviderRef.current || !isConnected) {
|
|
155
|
+
addEvent("system", "error", { error: "Not connected to websocket" });
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
wsProviderRef.current.unbindAll(channel);
|
|
161
|
+
const newSubscriptions = new Set(
|
|
162
|
+
[...subscriptions].filter(sub => !sub.startsWith(channel))
|
|
163
|
+
);
|
|
164
|
+
setSubscriptions(newSubscriptions);
|
|
165
|
+
addEvent("system", "unsubscribed-all", { channel });
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error("Failed to unsubscribe all:", error);
|
|
168
|
+
addEvent("system", "error", { error: String(error) });
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const addEvent = (channel: string, event: string, data: any) => {
|
|
173
|
+
const newEvent: WebSocketEvent = {
|
|
174
|
+
id: `${Date.now()}-${Math.random()}`,
|
|
175
|
+
timestamp: new Date(),
|
|
176
|
+
channel,
|
|
177
|
+
event,
|
|
178
|
+
data
|
|
179
|
+
};
|
|
180
|
+
setEvents(prev => [newEvent, ...prev].slice(0, 100)); // Keep last 100 events
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const clearEvents = () => {
|
|
184
|
+
setEvents([]);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<SidebarProvider
|
|
189
|
+
style={
|
|
190
|
+
{
|
|
191
|
+
"--sidebar-width": "calc(var(--spacing) * 72)",
|
|
192
|
+
"--header-height": "calc(var(--spacing) * 12)",
|
|
193
|
+
} as React.CSSProperties
|
|
194
|
+
}
|
|
195
|
+
>
|
|
196
|
+
<AppSidebar variant="inset" />
|
|
197
|
+
<SidebarInset>
|
|
198
|
+
<SiteHeader />
|
|
199
|
+
<div className="flex flex-1 flex-col">
|
|
200
|
+
<div className="flex flex-1 flex-col gap-4 p-4 md:gap-6 md:p-6">
|
|
201
|
+
<div className="flex flex-col gap-2">
|
|
202
|
+
<h1 className="text-3xl font-bold">WebSocket Testing</h1>
|
|
203
|
+
<p className="text-muted-foreground">
|
|
204
|
+
Test websocket connections using @bluecopa/core utilities
|
|
205
|
+
</p>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
209
|
+
{/* Connection Panel */}
|
|
210
|
+
<Card>
|
|
211
|
+
<CardHeader>
|
|
212
|
+
<CardTitle className="flex items-center gap-2">
|
|
213
|
+
Connection
|
|
214
|
+
<Badge variant={isConnected ? "default" : "secondary"}>
|
|
215
|
+
{isConnected ? "Connected" : "Disconnected"}
|
|
216
|
+
</Badge>
|
|
217
|
+
</CardTitle>
|
|
218
|
+
<CardDescription>
|
|
219
|
+
Connect to the Centrifugo websocket server
|
|
220
|
+
</CardDescription>
|
|
221
|
+
</CardHeader>
|
|
222
|
+
<CardContent className="space-y-4">
|
|
223
|
+
<div className="space-y-2">
|
|
224
|
+
<Label htmlFor="connection-url">
|
|
225
|
+
Connection URL (optional)
|
|
226
|
+
</Label>
|
|
227
|
+
<Input
|
|
228
|
+
id="connection-url"
|
|
229
|
+
placeholder="wss://your-centrifugo-server.com/connection/websocket"
|
|
230
|
+
value={connectionUrl}
|
|
231
|
+
onChange={(e) => setConnectionUrl(e.target.value)}
|
|
232
|
+
disabled={isConnected}
|
|
233
|
+
/>
|
|
234
|
+
<p className="text-xs text-muted-foreground">
|
|
235
|
+
Leave empty to use the default configured URL
|
|
236
|
+
</p>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="flex gap-2">
|
|
239
|
+
<Button
|
|
240
|
+
onClick={handleConnect}
|
|
241
|
+
disabled={isConnected}
|
|
242
|
+
className="flex-1"
|
|
243
|
+
>
|
|
244
|
+
Connect
|
|
245
|
+
</Button>
|
|
246
|
+
<Button
|
|
247
|
+
onClick={handleDisconnect}
|
|
248
|
+
disabled={!isConnected}
|
|
249
|
+
variant="destructive"
|
|
250
|
+
className="flex-1"
|
|
251
|
+
>
|
|
252
|
+
Disconnect
|
|
253
|
+
</Button>
|
|
254
|
+
</div>
|
|
255
|
+
</CardContent>
|
|
256
|
+
</Card>
|
|
257
|
+
|
|
258
|
+
{/* Subscription Panel */}
|
|
259
|
+
<Card>
|
|
260
|
+
<CardHeader>
|
|
261
|
+
<CardTitle>Subscriptions</CardTitle>
|
|
262
|
+
<CardDescription>
|
|
263
|
+
Subscribe to channels and events
|
|
264
|
+
</CardDescription>
|
|
265
|
+
</CardHeader>
|
|
266
|
+
<CardContent className="space-y-4">
|
|
267
|
+
<div className="space-y-2">
|
|
268
|
+
<Label htmlFor="channel">Channel</Label>
|
|
269
|
+
<Input
|
|
270
|
+
id="channel"
|
|
271
|
+
placeholder="test-channel"
|
|
272
|
+
value={channel}
|
|
273
|
+
onChange={(e) => setChannel(e.target.value)}
|
|
274
|
+
disabled={!isConnected}
|
|
275
|
+
/>
|
|
276
|
+
</div>
|
|
277
|
+
<div className="space-y-2">
|
|
278
|
+
<Label htmlFor="event">Event Name</Label>
|
|
279
|
+
<Input
|
|
280
|
+
id="event"
|
|
281
|
+
placeholder="message"
|
|
282
|
+
value={eventName}
|
|
283
|
+
onChange={(e) => setEventName(e.target.value)}
|
|
284
|
+
disabled={!isConnected}
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
<div className="flex flex-col gap-2">
|
|
288
|
+
<div className="flex gap-2">
|
|
289
|
+
<Button
|
|
290
|
+
onClick={handleSubscribe}
|
|
291
|
+
disabled={!isConnected}
|
|
292
|
+
className="flex-1"
|
|
293
|
+
size="sm"
|
|
294
|
+
>
|
|
295
|
+
Subscribe (Private)
|
|
296
|
+
</Button>
|
|
297
|
+
<Button
|
|
298
|
+
onClick={handleSubscribeGlobal}
|
|
299
|
+
disabled={!isConnected}
|
|
300
|
+
variant="outline"
|
|
301
|
+
className="flex-1"
|
|
302
|
+
size="sm"
|
|
303
|
+
>
|
|
304
|
+
Subscribe (Global)
|
|
305
|
+
</Button>
|
|
306
|
+
</div>
|
|
307
|
+
<div className="flex gap-2">
|
|
308
|
+
<Button
|
|
309
|
+
onClick={handleUnsubscribe}
|
|
310
|
+
disabled={!isConnected}
|
|
311
|
+
variant="secondary"
|
|
312
|
+
className="flex-1"
|
|
313
|
+
size="sm"
|
|
314
|
+
>
|
|
315
|
+
Unsubscribe
|
|
316
|
+
</Button>
|
|
317
|
+
<Button
|
|
318
|
+
onClick={handleUnsubscribeAll}
|
|
319
|
+
disabled={!isConnected}
|
|
320
|
+
variant="destructive"
|
|
321
|
+
className="flex-1"
|
|
322
|
+
size="sm"
|
|
323
|
+
>
|
|
324
|
+
Unsubscribe All
|
|
325
|
+
</Button>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</CardContent>
|
|
329
|
+
</Card>
|
|
330
|
+
</div>
|
|
331
|
+
|
|
332
|
+
{/* Active Subscriptions */}
|
|
333
|
+
<Card>
|
|
334
|
+
<CardHeader>
|
|
335
|
+
<CardTitle>Active Subscriptions ({subscriptions.size})</CardTitle>
|
|
336
|
+
</CardHeader>
|
|
337
|
+
<CardContent>
|
|
338
|
+
{subscriptions.size === 0 ? (
|
|
339
|
+
<p className="text-sm text-muted-foreground">No active subscriptions</p>
|
|
340
|
+
) : (
|
|
341
|
+
<div className="flex flex-wrap gap-2">
|
|
342
|
+
{[...subscriptions].map((sub) => (
|
|
343
|
+
<Badge key={sub} variant="outline">
|
|
344
|
+
{sub}
|
|
345
|
+
</Badge>
|
|
346
|
+
))}
|
|
347
|
+
</div>
|
|
348
|
+
)}
|
|
349
|
+
</CardContent>
|
|
350
|
+
</Card>
|
|
351
|
+
|
|
352
|
+
{/* Events Log */}
|
|
353
|
+
<Card>
|
|
354
|
+
<CardHeader>
|
|
355
|
+
<div className="flex items-center justify-between">
|
|
356
|
+
<div>
|
|
357
|
+
<CardTitle>Events Log ({events.length})</CardTitle>
|
|
358
|
+
<CardDescription>Real-time websocket events</CardDescription>
|
|
359
|
+
</div>
|
|
360
|
+
<Button
|
|
361
|
+
onClick={clearEvents}
|
|
362
|
+
variant="outline"
|
|
363
|
+
size="sm"
|
|
364
|
+
>
|
|
365
|
+
Clear
|
|
366
|
+
</Button>
|
|
367
|
+
</div>
|
|
368
|
+
</CardHeader>
|
|
369
|
+
<CardContent>
|
|
370
|
+
<div className="space-y-2 max-h-96 overflow-y-auto">
|
|
371
|
+
{events.length === 0 ? (
|
|
372
|
+
<p className="text-sm text-muted-foreground">No events yet</p>
|
|
373
|
+
) : (
|
|
374
|
+
events.map((event) => (
|
|
375
|
+
<div
|
|
376
|
+
key={event.id}
|
|
377
|
+
className="rounded-lg border p-3 space-y-1"
|
|
378
|
+
>
|
|
379
|
+
<div className="flex items-center justify-between">
|
|
380
|
+
<div className="flex items-center gap-2">
|
|
381
|
+
<Badge variant={event.channel === "system" ? "secondary" : "default"}>
|
|
382
|
+
{event.channel}
|
|
383
|
+
</Badge>
|
|
384
|
+
<span className="text-sm font-mono">{event.event}</span>
|
|
385
|
+
</div>
|
|
386
|
+
<span className="text-xs text-muted-foreground">
|
|
387
|
+
{event.timestamp.toLocaleTimeString()}
|
|
388
|
+
</span>
|
|
389
|
+
</div>
|
|
390
|
+
<Separator />
|
|
391
|
+
<pre className="text-xs bg-muted p-2 rounded overflow-x-auto">
|
|
392
|
+
{JSON.stringify(event.data, null, 2)}
|
|
393
|
+
</pre>
|
|
394
|
+
</div>
|
|
395
|
+
))
|
|
396
|
+
)}
|
|
397
|
+
</div>
|
|
398
|
+
</CardContent>
|
|
399
|
+
</Card>
|
|
400
|
+
|
|
401
|
+
{/* Usage Instructions */}
|
|
402
|
+
<Card>
|
|
403
|
+
<CardHeader>
|
|
404
|
+
<CardTitle>Usage Instructions</CardTitle>
|
|
405
|
+
</CardHeader>
|
|
406
|
+
<CardContent className="space-y-4">
|
|
407
|
+
<div className="space-y-2">
|
|
408
|
+
<h4 className="font-semibold">Before Using:</h4>
|
|
409
|
+
<pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
|
|
410
|
+
{`import { copaSetConfig } from "@bluecopa/react";
|
|
411
|
+
|
|
412
|
+
// Set configuration before connecting
|
|
413
|
+
copaSetConfig({
|
|
414
|
+
apiBaseUrl: "https://api.example.com",
|
|
415
|
+
accessToken: "your-access-token",
|
|
416
|
+
workspaceId: "your-workspace-id",
|
|
417
|
+
userId: "your-user-id"
|
|
418
|
+
});`}
|
|
419
|
+
</pre>
|
|
420
|
+
</div>
|
|
421
|
+
<div className="space-y-2">
|
|
422
|
+
<h4 className="font-semibold">Channel Types:</h4>
|
|
423
|
+
<ul className="list-disc list-inside text-sm space-y-1 text-muted-foreground">
|
|
424
|
+
<li>
|
|
425
|
+
<strong>Private:</strong> Format is{" "}
|
|
426
|
+
<code className="bg-muted px-1 rounded">private-{"{channel}"}-{"{userId}"}#{"{event}"}</code>
|
|
427
|
+
</li>
|
|
428
|
+
<li>
|
|
429
|
+
<strong>Global:</strong> Format is just the channel name, accessible by all users
|
|
430
|
+
</li>
|
|
431
|
+
</ul>
|
|
432
|
+
</div>
|
|
433
|
+
<div className="space-y-2">
|
|
434
|
+
<h4 className="font-semibold">Example Usage:</h4>
|
|
435
|
+
<ol className="list-decimal list-inside text-sm space-y-1 text-muted-foreground">
|
|
436
|
+
<li>Click "Connect" to establish a websocket connection</li>
|
|
437
|
+
<li>Enter a channel name (e.g., "notifications")</li>
|
|
438
|
+
<li>Enter an event name (e.g., "update")</li>
|
|
439
|
+
<li>Click "Subscribe (Private)" or "Subscribe (Global)"</li>
|
|
440
|
+
<li>Events will appear in the log below when received</li>
|
|
441
|
+
</ol>
|
|
442
|
+
</div>
|
|
443
|
+
</CardContent>
|
|
444
|
+
</Card>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
</SidebarInset>
|
|
448
|
+
</SidebarProvider>
|
|
449
|
+
);
|
|
450
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Routes, Route, Navigate } from "react-router-dom";
|
|
2
|
-
import { lazy } from "react";
|
|
3
2
|
import "./app.css";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import Dashboard from "./routes/dashboard";
|
|
4
|
+
import Comments from "./routes/comments";
|
|
5
|
+
import Websocket from "./routes/websocket";
|
|
6
|
+
import Payments from "./routes/payments";
|
|
7
7
|
|
|
8
8
|
export default function RouteConfig() {
|
|
9
9
|
return (
|
|
10
10
|
<Routes>
|
|
11
|
-
<Route path="/" element={<
|
|
11
|
+
<Route path="/" element={<Dashboard />} />
|
|
12
|
+
<Route path="/comments" element={<Comments />} />
|
|
13
|
+
<Route path="/websocket" element={<Websocket />} />
|
|
14
|
+
<Route path="/payments" element={<Payments />} />
|
|
12
15
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
13
16
|
</Routes>
|
|
14
17
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
System.register(['./__federation_fn_import-CzfA7kmP.js', './client-
|
|
1
|
+
System.register(['./__federation_fn_import-CzfA7kmP.js', './client-CsvW46cT.js'], (function (exports, module) {
|
|
2
2
|
'use strict';
|
|
3
3
|
var importShared, clientExports, jsxRuntimeExports, MemoryRouter, BrowserRouter, App;
|
|
4
4
|
return {
|
|
@@ -55,7 +55,17 @@ System.register(['./__federation_fn_import-CzfA7kmP.js', './client-Hh38T4k9.js']
|
|
|
55
55
|
root = null;
|
|
56
56
|
}
|
|
57
57
|
root = clientExports.createRoot(props.domElement);
|
|
58
|
-
root.render(
|
|
58
|
+
root.render(
|
|
59
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
60
|
+
MicrofrontendRoot,
|
|
61
|
+
{
|
|
62
|
+
isMicroFrontend: true,
|
|
63
|
+
props: {
|
|
64
|
+
basename: props.basename || "/app/external/microfrontend"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
);
|
|
59
69
|
console.log("Microfrontend mounted successfully");
|
|
60
70
|
return;
|
|
61
71
|
} catch (error) {
|