@@ -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" ;
1216import { 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" ;
1322import {
1423 BarChart ,
1524 Bar ,
@@ -34,6 +43,8 @@ import { CaDeviceSankey } from "/src/components/CippComponents/CaDeviceSankey";
3443import { AuthMethodSankey } from "/src/components/CippComponents/AuthMethodSankey" ;
3544import { DesktopDevicesSankey } from "/src/components/CippComponents/DesktopDevicesSankey" ;
3645import { MobileSankey } from "/src/components/CippComponents/MobileSankey" ;
46+ import { CippUniversalSearch } from "/src/components/CippCards/CippUniversalSearch.jsx" ;
47+ import { CippCopyToClipBoard } from "/src/components/CippComponents/CippCopyToClipboard.jsx" ;
3748import {
3849 People as UsersIcon ,
3950 Person as UserIcon ,
@@ -51,6 +62,72 @@ import {
5162
5263const 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