Skip to content

Commit db4d4ea

Browse files
authored
Merge pull request #681 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 9c6dbd0 + 3729bce commit db4d4ea

File tree

1 file changed

+252
-20
lines changed

1 file changed

+252
-20
lines changed

src/pages/dashboardv2/index.js

Lines changed: 252 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,17 @@ import {
88
Avatar,
99
Divider,
1010
Tooltip,
11+
Autocomplete,
12+
TextField,
13+
Button,
1114
} from "@mui/material";
15+
import { useState, useEffect } from "react";
1216
import { Grid } from "@mui/system";
17+
import { useSettings } from "/src/hooks/use-settings";
18+
import { ApiGetCall } from "/src/api/ApiCall.jsx";
19+
import Portals from "/src/data/portals";
20+
import { BulkActionsMenu } from "/src/components/bulk-actions-menu.js";
21+
import { ExecutiveReportButton } from "/src/components/ExecutiveReportButton.js";
1322
import {
1423
BarChart,
1524
Bar,
@@ -34,6 +43,8 @@ import { CaDeviceSankey } from "/src/components/CippComponents/CaDeviceSankey";
3443
import { AuthMethodSankey } from "/src/components/CippComponents/AuthMethodSankey";
3544
import { DesktopDevicesSankey } from "/src/components/CippComponents/DesktopDevicesSankey";
3645
import { MobileSankey } from "/src/components/CippComponents/MobileSankey";
46+
import { CippUniversalSearch } from "/src/components/CippCards/CippUniversalSearch.jsx";
47+
import { CippCopyToClipBoard } from "/src/components/CippComponents/CippCopyToClipboard.jsx";
3748
import {
3849
People as UsersIcon,
3950
Person as UserIcon,
@@ -51,6 +62,72 @@ import {
5162

5263
const Page = () => {
5364
const reportData = dashboardDemoData;
65+
const settings = useSettings();
66+
const { currentTenant } = settings;
67+
const [portalMenuItems, setPortalMenuItems] = useState([]);
68+
const [selectedReport, setSelectedReport] = useState(null);
69+
70+
const reportOptions = [
71+
"Select a report",
72+
"Executive Summary Report",
73+
"Security Assessment Report",
74+
"Compliance Report",
75+
"Device Inventory Report",
76+
];
77+
78+
const organization = ApiGetCall({
79+
url: "/api/ListOrg",
80+
queryKey: `${currentTenant}-ListOrg`,
81+
data: { tenantFilter: currentTenant },
82+
});
83+
84+
const dashboard = ApiGetCall({
85+
url: "/api/ListuserCounts",
86+
data: { tenantFilter: currentTenant },
87+
queryKey: `${currentTenant}-ListuserCounts`,
88+
});
89+
90+
const driftApi = ApiGetCall({
91+
url: "/api/listTenantDrift",
92+
data: {
93+
TenantFilter: currentTenant,
94+
},
95+
queryKey: `TenantDrift-${currentTenant}`,
96+
});
97+
98+
const currentTenantInfo = ApiGetCall({
99+
url: "/api/ListTenants",
100+
queryKey: `ListTenants`,
101+
});
102+
103+
useEffect(() => {
104+
if (currentTenantInfo.isSuccess) {
105+
const menuItems = Portals.map((portal) => ({
106+
label: portal.label,
107+
link: portal.url
108+
.replace(
109+
"%%tenantid%%",
110+
currentTenantInfo.data
111+
?.find((tenant) => tenant.defaultDomainName === currentTenant)
112+
?.customerId?.toLowerCase()
113+
)
114+
.replace(
115+
"%%customername%%",
116+
currentTenantInfo.data?.find((tenant) => tenant.defaultDomainName === currentTenant)
117+
?.displayName
118+
),
119+
external: portal.external,
120+
target: settings.UserSpecificSettings?.portalLinks || portal.target,
121+
icon: portal.icon,
122+
}));
123+
setPortalMenuItems(menuItems);
124+
}
125+
}, [
126+
currentTenantInfo.isSuccess,
127+
currentTenant,
128+
settings.portalLinks,
129+
settings.UserSpecificSettings,
130+
]);
54131

55132
const formatNumber = (num) => {
56133
if (!num && num !== 0) return "0";
@@ -72,6 +149,72 @@ const Page = () => {
72149
return (
73150
<Container maxWidth={false} sx={{ mt: 12, mb: 6 }}>
74151
<Box sx={{ width: "100%", mx: "auto" }}>
152+
{/* Dashboard Bar with Portals, Executive Report, and Universal Search */}
153+
<Grid container spacing={3} sx={{ mb: 4 }}>
154+
<Grid size={{ xs: 12, md: 6 }}>
155+
<Card sx={{ height: "100%" }}>
156+
<CardContent sx={{ display: "flex", alignItems: "center", gap: 2, p: 2 }}>
157+
<BulkActionsMenu
158+
buttonName="Portals"
159+
actions={portalMenuItems}
160+
disabled={!currentTenantInfo.isSuccess || portalMenuItems.length === 0}
161+
/>
162+
<ExecutiveReportButton
163+
tenantName={organization.data?.displayName}
164+
tenantId={organization.data?.id}
165+
userStats={{
166+
licensedUsers: dashboard.data?.LicUsers || 0,
167+
unlicensedUsers:
168+
dashboard.data?.Users && dashboard.data?.LicUsers
169+
? dashboard.data?.Users - dashboard.data?.LicUsers
170+
: 0,
171+
guests: dashboard.data?.Guests || 0,
172+
globalAdmins: dashboard.data?.Gas || 0,
173+
}}
174+
standardsData={driftApi.data}
175+
organizationData={organization.data}
176+
disabled={organization.isFetching || dashboard.isFetching}
177+
/>
178+
<Box sx={{ flex: 1 }}>
179+
<CippUniversalSearch />
180+
</Box>
181+
</CardContent>
182+
</Card>
183+
</Grid>
184+
<Grid size={{ xs: 12, md: 6 }}>
185+
<Card sx={{ height: "100%" }}>
186+
<CardContent sx={{ display: "flex", gap: 1.5, alignItems: "center", p: 2 }}>
187+
<Autocomplete
188+
size="small"
189+
options={reportOptions}
190+
value={selectedReport}
191+
onChange={(event, newValue) => setSelectedReport(newValue)}
192+
sx={{ flex: 1 }}
193+
renderInput={(params) => (
194+
<TextField {...params} label="Select a report" placeholder="Choose a report" />
195+
)}
196+
/>
197+
<Button
198+
variant="contained"
199+
size="small"
200+
sx={{ whiteSpace: "nowrap", minHeight: 40 }}
201+
>
202+
Create custom report
203+
</Button>
204+
<Button
205+
variant="outlined"
206+
color="error"
207+
size="small"
208+
sx={{ minHeight: 40 }}
209+
disabled={!selectedReport || selectedReport === "Select a report"}
210+
>
211+
Delete
212+
</Button>
213+
</CardContent>
214+
</Card>
215+
</Grid>
216+
</Grid>
217+
75218
{/* Tenant Overview Section - 3 Column Layout */}
76219
<Grid container spacing={3} sx={{ mb: 6 }}>
77220
{/* Column 1: Tenant Information */}
@@ -93,24 +236,53 @@ const Page = () => {
93236
Name
94237
</Typography>
95238
<Typography variant="body1" fontWeight={500}>
96-
{reportData.TenantName || "Not Available"}
239+
{organization.isFetching
240+
? "Loading..."
241+
: organization.data?.displayName || "Not Available"}
97242
</Typography>
98243
</Box>
99244
<Box>
100245
<Typography variant="caption" color="text.secondary">
101246
Tenant ID
102247
</Typography>
103-
<Typography variant="body2" fontFamily="monospace" fontSize="0.75rem">
104-
{reportData.TenantId || "Not Available"}
105-
</Typography>
248+
<Box sx={{ mt: 0.5 }}>
249+
{organization.isFetching ? (
250+
<Typography variant="body2" fontSize="0.75rem">
251+
Loading...
252+
</Typography>
253+
) : organization.data?.id ? (
254+
<CippCopyToClipBoard text={organization.data.id} type="chip" />
255+
) : (
256+
<Typography variant="body2" fontSize="0.75rem">
257+
Not Available
258+
</Typography>
259+
)}
260+
</Box>
106261
</Box>
107262
<Box>
108263
<Typography variant="caption" color="text.secondary">
109264
Primary Domain
110265
</Typography>
111-
<Typography variant="body1" fontWeight={500}>
112-
{reportData.Domain || "Not Available"}
113-
</Typography>
266+
<Box sx={{ mt: 0.5 }}>
267+
{organization.isFetching ? (
268+
<Typography variant="body2" fontSize="0.75rem">
269+
Loading...
270+
</Typography>
271+
) : organization.data?.verifiedDomains?.find((d) => d.isDefault)?.name ||
272+
currentTenant ? (
273+
<CippCopyToClipBoard
274+
text={
275+
organization.data?.verifiedDomains?.find((d) => d.isDefault)?.name ||
276+
currentTenant
277+
}
278+
type="chip"
279+
/>
280+
) : (
281+
<Typography variant="body2" fontSize="0.75rem">
282+
Not Available
283+
</Typography>
284+
)}
285+
</Box>
114286
</Box>
115287
</Box>
116288
</CardContent>
@@ -133,8 +305,15 @@ const Page = () => {
133305
borderRadius: 1,
134306
}}
135307
>
136-
<Avatar sx={{ bgcolor: "primary.main", width: 34, height: 34 }}>
137-
<UserIcon sx={{ fontSize: 24 }} />
308+
<Avatar
309+
sx={{
310+
bgcolor: "primary.main",
311+
color: "primary.contrastText",
312+
width: 34,
313+
height: 34,
314+
}}
315+
>
316+
<UserIcon sx={{ fontSize: 24, color: "inherit" }} />
138317
</Avatar>
139318
<Box>
140319
<Typography variant="caption" color="text.secondary" fontSize="0.7rem">
@@ -160,8 +339,15 @@ const Page = () => {
160339
borderRadius: 1,
161340
}}
162341
>
163-
<Avatar sx={{ bgcolor: "info.main", width: 34, height: 34 }}>
164-
<GuestIcon sx={{ fontSize: 24 }} />
342+
<Avatar
343+
sx={{
344+
bgcolor: "info.main",
345+
color: "info.contrastText",
346+
width: 34,
347+
height: 34,
348+
}}
349+
>
350+
<GuestIcon sx={{ fontSize: 24, color: "inherit" }} />
165351
</Avatar>
166352
<Box>
167353
<Typography variant="caption" color="text.secondary" fontSize="0.7rem">
@@ -187,8 +373,15 @@ const Page = () => {
187373
borderRadius: 1,
188374
}}
189375
>
190-
<Avatar sx={{ bgcolor: "secondary.main", width: 34, height: 34 }}>
191-
<GroupIcon sx={{ fontSize: 24 }} />
376+
<Avatar
377+
sx={{
378+
bgcolor: "secondary.main",
379+
color: "secondary.contrastText",
380+
width: 34,
381+
height: 34,
382+
}}
383+
>
384+
<GroupIcon sx={{ fontSize: 24, color: "inherit" }} />
192385
</Avatar>
193386
<Box>
194387
<Typography variant="caption" color="text.secondary" fontSize="0.7rem">
@@ -214,8 +407,15 @@ const Page = () => {
214407
borderRadius: 1,
215408
}}
216409
>
217-
<Avatar sx={{ bgcolor: "error.main", width: 34, height: 34 }}>
218-
<AppsIcon sx={{ fontSize: 24 }} />
410+
<Avatar
411+
sx={{
412+
bgcolor: "error.main",
413+
color: "error.contrastText",
414+
width: 34,
415+
height: 34,
416+
}}
417+
>
418+
<AppsIcon sx={{ fontSize: 24, color: "inherit" }} />
219419
</Avatar>
220420
<Box>
221421
<Typography variant="caption" color="text.secondary" fontSize="0.7rem">
@@ -241,8 +441,15 @@ const Page = () => {
241441
borderRadius: 1,
242442
}}
243443
>
244-
<Avatar sx={{ bgcolor: "warning.main", width: 34, height: 34 }}>
245-
<DevicesIcon sx={{ fontSize: 24 }} />
444+
<Avatar
445+
sx={{
446+
bgcolor: "warning.main",
447+
color: "warning.contrastText",
448+
width: 34,
449+
height: 34,
450+
}}
451+
>
452+
<DevicesIcon sx={{ fontSize: 24, color: "inherit" }} />
246453
</Avatar>
247454
<Box>
248455
<Typography variant="caption" color="text.secondary" fontSize="0.7rem">
@@ -268,8 +475,15 @@ const Page = () => {
268475
borderRadius: 1,
269476
}}
270477
>
271-
<Avatar sx={{ bgcolor: "success.main", width: 34, height: 34 }}>
272-
<ManagedIcon sx={{ fontSize: 24 }} />
478+
<Avatar
479+
sx={{
480+
bgcolor: "success.main",
481+
color: "success.contrastText",
482+
width: 34,
483+
height: 34,
484+
}}
485+
>
486+
<ManagedIcon sx={{ fontSize: 24, color: "inherit" }} />
273487
</Avatar>
274488
<Box>
275489
<Typography variant="caption" color="text.secondary" fontSize="0.7rem">
@@ -317,7 +531,7 @@ const Page = () => {
317531
</Typography>
318532
</Typography>
319533
</Box>
320-
<Box>
534+
<Box sx={{ mb: 2 }}>
321535
<Typography variant="caption" color="text.secondary">
322536
Devices
323537
</Typography>
@@ -334,6 +548,24 @@ const Page = () => {
334548
</Typography>
335549
</Typography>
336550
</Box>
551+
<Box>
552+
<Typography variant="caption" color="text.secondary">
553+
Last Data Collection
554+
</Typography>
555+
<Typography variant="body2" fontSize="0.75rem">
556+
{currentTenantInfo.isFetching
557+
? "Loading..."
558+
: currentTenantInfo.data?.find(
559+
(t) => t.defaultDomainName === currentTenant
560+
)?.LastRefresh
561+
? new Date(
562+
currentTenantInfo.data?.find(
563+
(t) => t.defaultDomainName === currentTenant
564+
)?.LastRefresh
565+
).toLocaleString()
566+
: "Not Available"}
567+
</Typography>
568+
</Box>
337569
</Box>
338570
<Box sx={{ width: "40%", maxWidth: 120, aspectRatio: 1 }}>
339571
<ResponsiveContainer width="100%" height="100%">

0 commit comments

Comments
 (0)