create-bluecopa-react-app 1.0.14 → 1.0.17
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 +1 -1
- package/templates/latest/Agent.md +124 -137
- package/templates/latest/README.md +17 -0
- package/templates/latest/app/app.css +1 -2
- package/templates/latest/app/components/app-sidebar.tsx +5 -0
- package/templates/latest/app/components/nav-user.tsx +4 -5
- package/templates/latest/app/routes/statements.tsx +493 -0
- package/templates/latest/app/routes.tsx +2 -0
- package/templates/latest/components.json +1 -1
- package/templates/latest/dist/assets/{__federation_expose_App-BIH7hwj_.js → __federation_expose_App-CcOhEUCE.js} +1 -1
- package/templates/latest/dist/assets/{client-CsvW46cT.js → client-uh-HfYnI.js} +6674 -5765
- package/templates/latest/dist/assets/{index-CFECuPSy.js → index-C1IOBHtM.js} +1 -1
- package/templates/latest/dist/assets/remoteEntry.css +49 -2
- package/templates/latest/dist/assets/remoteEntry.js +1 -1
- package/templates/latest/dist/index.html +2 -2
- package/templates/latest/package-lock.json +16 -90
- package/templates/latest/package.json +2 -2
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
// Note: These statement hooks require @bluecopa/react version 0.1.16 or higher
|
|
2
|
+
// Update your package.json to use the latest version that includes statement hooks
|
|
3
|
+
import {
|
|
4
|
+
useGetStatementData,
|
|
5
|
+
useGetViewsBySheetId,
|
|
6
|
+
useGetRunsByViewId,
|
|
7
|
+
useGetViewById,
|
|
8
|
+
useGetRunResultById,
|
|
9
|
+
useCreateStatementRun,
|
|
10
|
+
} from "@bluecopa/react";
|
|
11
|
+
import { AppSidebar } from "~/components/app-sidebar";
|
|
12
|
+
import { SiteHeader } from "~/components/site-header";
|
|
13
|
+
import { SidebarInset, SidebarProvider } from "~/components/ui/sidebar";
|
|
14
|
+
import { Badge } from "~/components/ui/badge";
|
|
15
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
|
|
16
|
+
import {
|
|
17
|
+
Table,
|
|
18
|
+
TableBody,
|
|
19
|
+
TableCell,
|
|
20
|
+
TableHead,
|
|
21
|
+
TableHeader,
|
|
22
|
+
TableRow,
|
|
23
|
+
} from "~/components/ui/table";
|
|
24
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
|
|
25
|
+
import { Skeleton } from "~/components/ui/skeleton";
|
|
26
|
+
import { Button } from "~/components/ui/button";
|
|
27
|
+
import { useState } from "react";
|
|
28
|
+
import { toast } from "sonner";
|
|
29
|
+
|
|
30
|
+
export default function StatementsPage() {
|
|
31
|
+
// Example 1: Statement without viewId (uses default view)
|
|
32
|
+
const statementId1 = "MDYK9CU8NR1S41AFAOEX";
|
|
33
|
+
|
|
34
|
+
// Example 2: Statement with specific viewId
|
|
35
|
+
const statementId2 = "MGIZ7GD08NQJ71SK8RA7";
|
|
36
|
+
const viewId2 = "MGJ1ZF0JN53B0V0YH10Z";
|
|
37
|
+
|
|
38
|
+
const [selectedStatement, setSelectedStatement] = useState<"example1" | "example2">("example1");
|
|
39
|
+
const currentStatementId = selectedStatement === "example1" ? statementId1 : statementId2;
|
|
40
|
+
const currentViewId = selectedStatement === "example2" ? viewId2 : undefined;
|
|
41
|
+
|
|
42
|
+
// Fetch statement data
|
|
43
|
+
const {
|
|
44
|
+
data: statementData,
|
|
45
|
+
isLoading: statementDataLoading,
|
|
46
|
+
error: statementDataError,
|
|
47
|
+
refetch: refetchStatementData,
|
|
48
|
+
} = useGetStatementData(currentStatementId, currentViewId, undefined, {
|
|
49
|
+
enabled: !!currentStatementId,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Fetch views by sheet ID (if we had sheetId, but we'll use this for demonstration)
|
|
53
|
+
// Note: In real usage, you'd get sheetId from the workbook first
|
|
54
|
+
const [selectedViewId, setSelectedViewId] = useState<string | undefined>(currentViewId);
|
|
55
|
+
|
|
56
|
+
// Fetch runs by view ID (if we have a viewId)
|
|
57
|
+
const {
|
|
58
|
+
data: runsData,
|
|
59
|
+
isLoading: runsLoading,
|
|
60
|
+
error: runsError,
|
|
61
|
+
} = useGetRunsByViewId(selectedViewId, {
|
|
62
|
+
enabled: !!selectedViewId,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Fetch specific view details
|
|
66
|
+
const {
|
|
67
|
+
data: viewData,
|
|
68
|
+
isLoading: viewLoading,
|
|
69
|
+
error: viewError,
|
|
70
|
+
} = useGetViewById(selectedViewId, {
|
|
71
|
+
enabled: !!selectedViewId,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Mutation hook for creating a new run
|
|
75
|
+
const createRunMutation = useCreateStatementRun({
|
|
76
|
+
onSuccess: (data: { runId: string }) => {
|
|
77
|
+
toast.success(`New run created successfully! Run ID: ${data.runId}`);
|
|
78
|
+
// Refetch statement data and runs after creating a new run
|
|
79
|
+
refetchStatementData();
|
|
80
|
+
},
|
|
81
|
+
onError: (error: Error) => {
|
|
82
|
+
toast.error(`Failed to create run: ${error.message}`);
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const handleCreateRun = () => {
|
|
87
|
+
if (!currentStatementId) {
|
|
88
|
+
toast.error("Please select a statement first");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
createRunMutation.mutate({
|
|
93
|
+
statementId: currentStatementId,
|
|
94
|
+
viewId: currentViewId,
|
|
95
|
+
options: {
|
|
96
|
+
name: `Run ${new Date().toLocaleString()}`,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Extract data from statement result
|
|
102
|
+
const statementRows = statementData?.data || [];
|
|
103
|
+
const statementErrors = statementData?.error || { lineErrors: [], comparisonErrors: {} };
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<SidebarProvider
|
|
107
|
+
style={
|
|
108
|
+
{
|
|
109
|
+
"--sidebar-width": "calc(var(--spacing) * 72)",
|
|
110
|
+
"--header-height": "calc(var(--spacing) * 12)",
|
|
111
|
+
} as React.CSSProperties
|
|
112
|
+
}
|
|
113
|
+
>
|
|
114
|
+
<AppSidebar variant="inset" />
|
|
115
|
+
<SidebarInset>
|
|
116
|
+
<SiteHeader />
|
|
117
|
+
<div className="flex flex-1 flex-col">
|
|
118
|
+
<div className="@container/main flex flex-1 flex-col gap-2">
|
|
119
|
+
<div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
|
|
120
|
+
{/* Header Section */}
|
|
121
|
+
<div className="px-4 lg:px-6">
|
|
122
|
+
<div className="flex items-center justify-between">
|
|
123
|
+
<div>
|
|
124
|
+
<h1 className="text-3xl font-bold tracking-tight">Statement Viewer</h1>
|
|
125
|
+
<p className="text-muted-foreground">
|
|
126
|
+
View and manage statement data using BlueCopa statement hooks
|
|
127
|
+
</p>
|
|
128
|
+
</div>
|
|
129
|
+
<div className="flex gap-2">
|
|
130
|
+
<Button
|
|
131
|
+
variant={selectedStatement === "example1" ? "default" : "outline"}
|
|
132
|
+
onClick={() => setSelectedStatement("example1")}
|
|
133
|
+
>
|
|
134
|
+
Example 1
|
|
135
|
+
</Button>
|
|
136
|
+
<Button
|
|
137
|
+
variant={selectedStatement === "example2" ? "default" : "outline"}
|
|
138
|
+
onClick={() => setSelectedStatement("example2")}
|
|
139
|
+
>
|
|
140
|
+
Example 2
|
|
141
|
+
</Button>
|
|
142
|
+
<Button
|
|
143
|
+
onClick={handleCreateRun}
|
|
144
|
+
disabled={createRunMutation.isPending || !currentStatementId}
|
|
145
|
+
>
|
|
146
|
+
{createRunMutation.isPending ? "Creating..." : "Create New Run"}
|
|
147
|
+
</Button>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
{/* Statement Info Cards */}
|
|
153
|
+
<div className="grid gap-4 px-4 md:grid-cols-3 lg:px-6">
|
|
154
|
+
<Card>
|
|
155
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
156
|
+
<CardTitle className="text-sm font-medium">Statement ID</CardTitle>
|
|
157
|
+
</CardHeader>
|
|
158
|
+
<CardContent>
|
|
159
|
+
<div className="text-lg font-mono text-xs break-all">
|
|
160
|
+
{currentStatementId}
|
|
161
|
+
</div>
|
|
162
|
+
</CardContent>
|
|
163
|
+
</Card>
|
|
164
|
+
<Card>
|
|
165
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
166
|
+
<CardTitle className="text-sm font-medium">View ID</CardTitle>
|
|
167
|
+
</CardHeader>
|
|
168
|
+
<CardContent>
|
|
169
|
+
<div className="text-lg font-mono text-xs break-all">
|
|
170
|
+
{currentViewId || "Default View"}
|
|
171
|
+
</div>
|
|
172
|
+
</CardContent>
|
|
173
|
+
</Card>
|
|
174
|
+
<Card>
|
|
175
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
176
|
+
<CardTitle className="text-sm font-medium">Data Rows</CardTitle>
|
|
177
|
+
</CardHeader>
|
|
178
|
+
<CardContent>
|
|
179
|
+
<div className="text-2xl font-bold">
|
|
180
|
+
{statementDataLoading ? (
|
|
181
|
+
<Skeleton className="h-8 w-16" />
|
|
182
|
+
) : (
|
|
183
|
+
statementRows.length
|
|
184
|
+
)}
|
|
185
|
+
</div>
|
|
186
|
+
<p className="text-xs text-muted-foreground">
|
|
187
|
+
{statementDataError ? "Error loading data" : "Total rows"}
|
|
188
|
+
</p>
|
|
189
|
+
</CardContent>
|
|
190
|
+
</Card>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
{/* Tabs for different views */}
|
|
194
|
+
<div className="px-4 lg:px-6">
|
|
195
|
+
<Tabs defaultValue="data" className="w-full">
|
|
196
|
+
<TabsList>
|
|
197
|
+
<TabsTrigger value="data">
|
|
198
|
+
Statement Data
|
|
199
|
+
{statementDataLoading && <Skeleton className="ml-2 h-4 w-8" />}
|
|
200
|
+
</TabsTrigger>
|
|
201
|
+
<TabsTrigger value="runs">
|
|
202
|
+
Runs
|
|
203
|
+
{runsLoading && <Skeleton className="ml-2 h-4 w-8" />}
|
|
204
|
+
</TabsTrigger>
|
|
205
|
+
<TabsTrigger value="view">
|
|
206
|
+
View Details
|
|
207
|
+
{viewLoading && <Skeleton className="ml-2 h-4 w-8" />}
|
|
208
|
+
</TabsTrigger>
|
|
209
|
+
</TabsList>
|
|
210
|
+
|
|
211
|
+
{/* Statement Data Tab */}
|
|
212
|
+
<TabsContent value="data" className="space-y-4">
|
|
213
|
+
<Card>
|
|
214
|
+
<CardHeader>
|
|
215
|
+
<CardTitle>Statement Data</CardTitle>
|
|
216
|
+
<CardDescription>
|
|
217
|
+
{statementDataError
|
|
218
|
+
? `Error: ${statementDataError.message}`
|
|
219
|
+
: `Viewing data for statement ${currentStatementId}`}
|
|
220
|
+
</CardDescription>
|
|
221
|
+
</CardHeader>
|
|
222
|
+
<CardContent>
|
|
223
|
+
{statementDataLoading ? (
|
|
224
|
+
<div className="space-y-2">
|
|
225
|
+
{[...Array(5)].map((_, i) => (
|
|
226
|
+
<Skeleton key={i} className="h-12 w-full" />
|
|
227
|
+
))}
|
|
228
|
+
</div>
|
|
229
|
+
) : statementDataError ? (
|
|
230
|
+
<div className="text-center py-8 text-destructive">
|
|
231
|
+
<p className="font-medium">Failed to load statement data</p>
|
|
232
|
+
<p className="text-sm text-muted-foreground mt-2">
|
|
233
|
+
{statementDataError.message}
|
|
234
|
+
</p>
|
|
235
|
+
<Button
|
|
236
|
+
onClick={() => refetchStatementData()}
|
|
237
|
+
className="mt-4"
|
|
238
|
+
variant="outline"
|
|
239
|
+
>
|
|
240
|
+
Retry
|
|
241
|
+
</Button>
|
|
242
|
+
</div>
|
|
243
|
+
) : statementRows.length === 0 ? (
|
|
244
|
+
<div className="text-center py-8 text-muted-foreground">
|
|
245
|
+
No data available
|
|
246
|
+
</div>
|
|
247
|
+
) : (
|
|
248
|
+
<div className="rounded-md border overflow-x-auto">
|
|
249
|
+
<Table>
|
|
250
|
+
<TableHeader>
|
|
251
|
+
<TableRow>
|
|
252
|
+
{Object.keys(statementRows[0] || {}).map((key) => (
|
|
253
|
+
<TableHead key={key} className="capitalize">
|
|
254
|
+
{key.replace(/_/g, " ")}
|
|
255
|
+
</TableHead>
|
|
256
|
+
))}
|
|
257
|
+
</TableRow>
|
|
258
|
+
</TableHeader>
|
|
259
|
+
<TableBody>
|
|
260
|
+
{statementRows.slice(0, 100).map((row: any, index: number) => (
|
|
261
|
+
<TableRow key={index}>
|
|
262
|
+
{Object.keys(statementRows[0] || {}).map((key) => (
|
|
263
|
+
<TableCell key={key} className="font-mono text-xs">
|
|
264
|
+
{typeof row[key] === "object"
|
|
265
|
+
? JSON.stringify(row[key])
|
|
266
|
+
: String(row[key] || "-")}
|
|
267
|
+
</TableCell>
|
|
268
|
+
))}
|
|
269
|
+
</TableRow>
|
|
270
|
+
))}
|
|
271
|
+
</TableBody>
|
|
272
|
+
</Table>
|
|
273
|
+
{statementRows.length > 100 && (
|
|
274
|
+
<div className="p-4 text-center text-sm text-muted-foreground">
|
|
275
|
+
Showing first 100 of {statementRows.length} rows
|
|
276
|
+
</div>
|
|
277
|
+
)}
|
|
278
|
+
</div>
|
|
279
|
+
)}
|
|
280
|
+
</CardContent>
|
|
281
|
+
</Card>
|
|
282
|
+
|
|
283
|
+
{/* Errors Section */}
|
|
284
|
+
{statementErrors.lineErrors?.length > 0 && (
|
|
285
|
+
<Card>
|
|
286
|
+
<CardHeader>
|
|
287
|
+
<CardTitle className="text-destructive">Data Errors</CardTitle>
|
|
288
|
+
<CardDescription>
|
|
289
|
+
{statementErrors.lineErrors.length} error(s) found
|
|
290
|
+
</CardDescription>
|
|
291
|
+
</CardHeader>
|
|
292
|
+
<CardContent>
|
|
293
|
+
<div className="space-y-2">
|
|
294
|
+
{statementErrors.lineErrors.map((error: any, index: number) => (
|
|
295
|
+
<div
|
|
296
|
+
key={index}
|
|
297
|
+
className="p-3 border border-destructive/50 rounded-md bg-destructive/5"
|
|
298
|
+
>
|
|
299
|
+
<p className="text-sm font-medium text-destructive">
|
|
300
|
+
Line {error.line || index + 1}
|
|
301
|
+
</p>
|
|
302
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
303
|
+
{error.message || JSON.stringify(error)}
|
|
304
|
+
</p>
|
|
305
|
+
</div>
|
|
306
|
+
))}
|
|
307
|
+
</div>
|
|
308
|
+
</CardContent>
|
|
309
|
+
</Card>
|
|
310
|
+
)}
|
|
311
|
+
</TabsContent>
|
|
312
|
+
|
|
313
|
+
{/* Runs Tab */}
|
|
314
|
+
<TabsContent value="runs" className="space-y-4">
|
|
315
|
+
<Card>
|
|
316
|
+
<CardHeader>
|
|
317
|
+
<CardTitle>Statement Runs</CardTitle>
|
|
318
|
+
<CardDescription>
|
|
319
|
+
{runsError
|
|
320
|
+
? `Error: ${runsError.message}`
|
|
321
|
+
: selectedViewId
|
|
322
|
+
? `Viewing runs for view ${selectedViewId}`
|
|
323
|
+
: "Select a view to see runs"}
|
|
324
|
+
</CardDescription>
|
|
325
|
+
</CardHeader>
|
|
326
|
+
<CardContent>
|
|
327
|
+
{!selectedViewId ? (
|
|
328
|
+
<div className="text-center py-8 text-muted-foreground">
|
|
329
|
+
No view selected. Select Example 2 to see runs for a specific view.
|
|
330
|
+
</div>
|
|
331
|
+
) : runsLoading ? (
|
|
332
|
+
<div className="space-y-2">
|
|
333
|
+
{[...Array(3)].map((_, i) => (
|
|
334
|
+
<Skeleton key={i} className="h-12 w-full" />
|
|
335
|
+
))}
|
|
336
|
+
</div>
|
|
337
|
+
) : runsError ? (
|
|
338
|
+
<div className="text-center py-8 text-destructive">
|
|
339
|
+
<p className="font-medium">Failed to load runs</p>
|
|
340
|
+
<p className="text-sm text-muted-foreground mt-2">
|
|
341
|
+
{runsError.message}
|
|
342
|
+
</p>
|
|
343
|
+
</div>
|
|
344
|
+
) : !runsData || runsData.length === 0 ? (
|
|
345
|
+
<div className="text-center py-8 text-muted-foreground">
|
|
346
|
+
No runs found for this view
|
|
347
|
+
</div>
|
|
348
|
+
) : (
|
|
349
|
+
<div className="rounded-md border overflow-x-auto">
|
|
350
|
+
<Table>
|
|
351
|
+
<TableHeader>
|
|
352
|
+
<TableRow>
|
|
353
|
+
<TableHead>Run ID</TableHead>
|
|
354
|
+
<TableHead>Name</TableHead>
|
|
355
|
+
<TableHead>Status</TableHead>
|
|
356
|
+
<TableHead>Created Date</TableHead>
|
|
357
|
+
<TableHead>Last Modified</TableHead>
|
|
358
|
+
</TableRow>
|
|
359
|
+
</TableHeader>
|
|
360
|
+
<TableBody>
|
|
361
|
+
{runsData.map((run: any) => (
|
|
362
|
+
<TableRow key={run.id}>
|
|
363
|
+
<TableCell className="font-mono text-xs">
|
|
364
|
+
{run.id || "N/A"}
|
|
365
|
+
</TableCell>
|
|
366
|
+
<TableCell className="font-medium">
|
|
367
|
+
{run.name || "Unnamed Run"}
|
|
368
|
+
</TableCell>
|
|
369
|
+
<TableCell>
|
|
370
|
+
<Badge
|
|
371
|
+
variant={
|
|
372
|
+
run.status === "SUCCEEDED"
|
|
373
|
+
? "default"
|
|
374
|
+
: run.status === "FAILED"
|
|
375
|
+
? "destructive"
|
|
376
|
+
: "secondary"
|
|
377
|
+
}
|
|
378
|
+
>
|
|
379
|
+
{run.status || "UNKNOWN"}
|
|
380
|
+
</Badge>
|
|
381
|
+
</TableCell>
|
|
382
|
+
<TableCell>
|
|
383
|
+
{run.createdDate
|
|
384
|
+
? new Date(run.createdDate).toLocaleString()
|
|
385
|
+
: "N/A"}
|
|
386
|
+
</TableCell>
|
|
387
|
+
<TableCell>
|
|
388
|
+
{run.lastModifiedDate
|
|
389
|
+
? new Date(run.lastModifiedDate).toLocaleString()
|
|
390
|
+
: "N/A"}
|
|
391
|
+
</TableCell>
|
|
392
|
+
</TableRow>
|
|
393
|
+
))}
|
|
394
|
+
</TableBody>
|
|
395
|
+
</Table>
|
|
396
|
+
</div>
|
|
397
|
+
)}
|
|
398
|
+
</CardContent>
|
|
399
|
+
</Card>
|
|
400
|
+
</TabsContent>
|
|
401
|
+
|
|
402
|
+
{/* View Details Tab */}
|
|
403
|
+
<TabsContent value="view" className="space-y-4">
|
|
404
|
+
<Card>
|
|
405
|
+
<CardHeader>
|
|
406
|
+
<CardTitle>View Details</CardTitle>
|
|
407
|
+
<CardDescription>
|
|
408
|
+
{viewError
|
|
409
|
+
? `Error: ${viewError.message}`
|
|
410
|
+
: selectedViewId
|
|
411
|
+
? `Details for view ${selectedViewId}`
|
|
412
|
+
: "Select a view to see details"}
|
|
413
|
+
</CardDescription>
|
|
414
|
+
</CardHeader>
|
|
415
|
+
<CardContent>
|
|
416
|
+
{!selectedViewId ? (
|
|
417
|
+
<div className="text-center py-8 text-muted-foreground">
|
|
418
|
+
No view selected. Select Example 2 to see view details.
|
|
419
|
+
</div>
|
|
420
|
+
) : viewLoading ? (
|
|
421
|
+
<div className="space-y-2">
|
|
422
|
+
{[...Array(5)].map((_, i) => (
|
|
423
|
+
<Skeleton key={i} className="h-8 w-full" />
|
|
424
|
+
))}
|
|
425
|
+
</div>
|
|
426
|
+
) : viewError ? (
|
|
427
|
+
<div className="text-center py-8 text-destructive">
|
|
428
|
+
<p className="font-medium">Failed to load view details</p>
|
|
429
|
+
<p className="text-sm text-muted-foreground mt-2">
|
|
430
|
+
{viewError.message}
|
|
431
|
+
</p>
|
|
432
|
+
</div>
|
|
433
|
+
) : !viewData ? (
|
|
434
|
+
<div className="text-center py-8 text-muted-foreground">
|
|
435
|
+
No view data available
|
|
436
|
+
</div>
|
|
437
|
+
) : (
|
|
438
|
+
<div className="space-y-4">
|
|
439
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
440
|
+
<div>
|
|
441
|
+
<p className="text-sm font-medium text-muted-foreground">View ID</p>
|
|
442
|
+
<p className="text-sm font-mono break-all">{viewData.id || "N/A"}</p>
|
|
443
|
+
</div>
|
|
444
|
+
<div>
|
|
445
|
+
<p className="text-sm font-medium text-muted-foreground">Name</p>
|
|
446
|
+
<p className="text-sm">{viewData.name || "N/A"}</p>
|
|
447
|
+
</div>
|
|
448
|
+
<div>
|
|
449
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
450
|
+
Created Date
|
|
451
|
+
</p>
|
|
452
|
+
<p className="text-sm">
|
|
453
|
+
{viewData.createdDate
|
|
454
|
+
? new Date(viewData.createdDate).toLocaleString()
|
|
455
|
+
: "N/A"}
|
|
456
|
+
</p>
|
|
457
|
+
</div>
|
|
458
|
+
<div>
|
|
459
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
460
|
+
Last Modified
|
|
461
|
+
</p>
|
|
462
|
+
<p className="text-sm">
|
|
463
|
+
{viewData.lastModifiedDate
|
|
464
|
+
? new Date(viewData.lastModifiedDate).toLocaleString()
|
|
465
|
+
: "N/A"}
|
|
466
|
+
</p>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
{viewData.customFields && (
|
|
470
|
+
<div>
|
|
471
|
+
<p className="text-sm font-medium text-muted-foreground mb-2">
|
|
472
|
+
Custom Fields
|
|
473
|
+
</p>
|
|
474
|
+
<pre className="p-4 bg-muted rounded-md text-xs overflow-x-auto">
|
|
475
|
+
{JSON.stringify(viewData.customFields, null, 2)}
|
|
476
|
+
</pre>
|
|
477
|
+
</div>
|
|
478
|
+
)}
|
|
479
|
+
</div>
|
|
480
|
+
)}
|
|
481
|
+
</CardContent>
|
|
482
|
+
</Card>
|
|
483
|
+
</TabsContent>
|
|
484
|
+
</Tabs>
|
|
485
|
+
</div>
|
|
486
|
+
</div>
|
|
487
|
+
</div>
|
|
488
|
+
</div>
|
|
489
|
+
</SidebarInset>
|
|
490
|
+
</SidebarProvider>
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
@@ -4,6 +4,7 @@ import Dashboard from "./routes/dashboard";
|
|
|
4
4
|
import Comments from "./routes/comments";
|
|
5
5
|
import Websocket from "./routes/websocket";
|
|
6
6
|
import Payments from "./routes/payments";
|
|
7
|
+
import Statements from "./routes/statements";
|
|
7
8
|
|
|
8
9
|
export default function RouteConfig() {
|
|
9
10
|
return (
|
|
@@ -12,6 +13,7 @@ export default function RouteConfig() {
|
|
|
12
13
|
<Route path="/comments" element={<Comments />} />
|
|
13
14
|
<Route path="/websocket" element={<Websocket />} />
|
|
14
15
|
<Route path="/payments" element={<Payments />} />
|
|
16
|
+
<Route path="/statements" element={<Statements />} />
|
|
15
17
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
16
18
|
</Routes>
|
|
17
19
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
System.register(['./__federation_fn_import-CzfA7kmP.js', './client-
|
|
1
|
+
System.register(['./__federation_fn_import-CzfA7kmP.js', './client-uh-HfYnI.js'], (function (exports, module) {
|
|
2
2
|
'use strict';
|
|
3
3
|
var importShared, clientExports, jsxRuntimeExports, MemoryRouter, BrowserRouter, App;
|
|
4
4
|
return {
|