mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-07-26 11:59:14 +00:00
Improve dashboard data handling and visualization. Updated data fetching and chart configurations for better data display.
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/0ab49ba3-2a0b-4884-9cf6-dbdb4748e98c.jpg
This commit is contained in:
@@ -84,10 +84,12 @@ export function DashboardLayout({
|
||||
type: widget.type,
|
||||
dataSource: widget.data[0]?.dataSource || "",
|
||||
config: {
|
||||
xAxis: widget.config.xAxis,
|
||||
yAxis: Array.isArray(widget.config.yAxis) ? widget.config.yAxis : [widget.config.yAxis].filter(Boolean),
|
||||
dimensions: widget.config.dimensions || [],
|
||||
metrics: widget.config.metrics || [],
|
||||
xAxis: widget.config.xAxis || "",
|
||||
yAxis: Array.isArray(widget.config.yAxis)
|
||||
? widget.config.yAxis.filter(Boolean) as string[]
|
||||
: (widget.config.yAxis ? [widget.config.yAxis as string] : []),
|
||||
dimensions: (widget.config.dimensions || []).filter(Boolean) as string[],
|
||||
metrics: (widget.config.metrics || []).filter(Boolean) as string[],
|
||||
showLegend: widget.config.showLegend ?? true,
|
||||
stacked: widget.config.stacked ?? false,
|
||||
precision: widget.config.precision ?? 2,
|
||||
|
||||
@@ -125,6 +125,7 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
if (!data || data.length === 0) return <p className="text-muted-foreground text-center py-4">No data available</p>;
|
||||
|
||||
const { xAxis, yAxis, dimensions, metrics, colors = COLORS, showLegend = true, stacked = false } = config;
|
||||
const xAxisKey = xAxis as string;
|
||||
|
||||
switch (type) {
|
||||
case 'bar':
|
||||
@@ -132,7 +133,7 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<BarChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 30 }}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={xAxis} />
|
||||
<XAxis dataKey={xAxisKey} />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
{showLegend && <Legend />}
|
||||
@@ -140,12 +141,12 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
? yAxis.map((axis, index) => (
|
||||
<Bar
|
||||
key={axis}
|
||||
dataKey={axis}
|
||||
dataKey={axis as string}
|
||||
stackId={stacked ? "a" : undefined}
|
||||
fill={colors[index % colors.length]}
|
||||
/>
|
||||
))
|
||||
: yAxis ? <Bar dataKey={yAxis} fill={colors[0]} /> : null
|
||||
: yAxis ? <Bar dataKey={yAxis as string} fill={colors[0]} /> : null
|
||||
}
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
@@ -156,7 +157,7 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<LineChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 30 }}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={xAxis} />
|
||||
<XAxis dataKey={xAxisKey} />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
{showLegend && <Legend />}
|
||||
@@ -165,12 +166,12 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
<Line
|
||||
key={axis}
|
||||
type="monotone"
|
||||
dataKey={axis}
|
||||
dataKey={axis as string}
|
||||
stroke={colors[index % colors.length]}
|
||||
activeDot={{ r: 8 }}
|
||||
/>
|
||||
))
|
||||
: yAxis ? <Line type="monotone" dataKey={yAxis} stroke={colors[0]} activeDot={{ r: 8 }} /> : null
|
||||
: yAxis ? <Line type="monotone" dataKey={yAxis as string} stroke={colors[0]} activeDot={{ r: 8 }} /> : null
|
||||
}
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
@@ -181,7 +182,7 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<AreaChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 30 }}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey={xAxis} />
|
||||
<XAxis dataKey={xAxisKey} />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
{showLegend && <Legend />}
|
||||
@@ -190,13 +191,13 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
<Area
|
||||
key={axis}
|
||||
type="monotone"
|
||||
dataKey={axis}
|
||||
dataKey={axis as string}
|
||||
stackId={stacked ? "a" : `${index}`}
|
||||
fill={colors[index % colors.length]}
|
||||
stroke={colors[index % colors.length]}
|
||||
/>
|
||||
))
|
||||
: yAxis ? <Area type="monotone" dataKey={yAxis} fill={colors[0]} stroke={colors[0]} /> : null
|
||||
: yAxis ? <Area type="monotone" dataKey={yAxis as string} fill={colors[0]} stroke={colors[0]} /> : null
|
||||
}
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
@@ -210,8 +211,8 @@ export function DashboardWidget({ id, title, type, data, config, onEdit, onDelet
|
||||
(Array.isArray(yAxis) && yAxis.length > 0 ? yAxis[0] :
|
||||
(typeof yAxis === 'string' ? yAxis : "value"));
|
||||
|
||||
const name = item[dimensionField];
|
||||
const value = item[metricField];
|
||||
const name = item[dimensionField as string];
|
||||
const value = item[metricField as string];
|
||||
return { name, value: Number(value) };
|
||||
}).filter(item => !isNaN(item.value));
|
||||
|
||||
|
||||
@@ -64,19 +64,20 @@ export default function DashboardPage() {
|
||||
const { data: usersData, isLoading: isLoadingUsers } = useQuery<any>({
|
||||
queryKey: ['/api/user-dashboard-data'],
|
||||
queryFn: async () => {
|
||||
// This would normally come from an API endpoint
|
||||
// Here we're implementing a mock data fetcher for the dashboard
|
||||
const response = await fetch('/api/ad/users?properties=name,mail,title,department,employeeId,manager,memberOf,whenCreated');
|
||||
const response = await fetch('/api/user-dashboard-data');
|
||||
if (!response.ok) throw new Error('Failed to fetch users');
|
||||
const users = await response.json();
|
||||
|
||||
// Get the structure of the data to determine field types
|
||||
const fields = getFieldTypes(users.data || []);
|
||||
const userData = users.data || [];
|
||||
const fields = getFieldTypes(userData);
|
||||
|
||||
console.log('User data fields:', fields);
|
||||
|
||||
return {
|
||||
id: 'users',
|
||||
name: 'Active Directory Users',
|
||||
data: users.data || [],
|
||||
data: userData,
|
||||
fields,
|
||||
};
|
||||
},
|
||||
@@ -87,17 +88,20 @@ export default function DashboardPage() {
|
||||
const { data: computersData, isLoading: isLoadingComputers } = useQuery<any>({
|
||||
queryKey: ['/api/computer-dashboard-data'],
|
||||
queryFn: async () => {
|
||||
const response = await fetch('/api/ad/computers?properties=name,operatingSystem,operatingSystemVersion,whenCreated,lastLogonTimestamp,enabled,memberOf');
|
||||
const response = await fetch('/api/computer-dashboard-data');
|
||||
if (!response.ok) throw new Error('Failed to fetch computers');
|
||||
const computers = await response.json();
|
||||
|
||||
// Get the structure of the data to determine field types
|
||||
const fields = getFieldTypes(computers.data || []);
|
||||
const computerData = computers.data || [];
|
||||
const fields = getFieldTypes(computerData);
|
||||
|
||||
console.log('Computer data fields:', fields);
|
||||
|
||||
return {
|
||||
id: 'computers',
|
||||
name: 'Active Directory Computers',
|
||||
data: computers.data || [],
|
||||
data: computerData,
|
||||
fields,
|
||||
};
|
||||
},
|
||||
@@ -108,17 +112,20 @@ export default function DashboardPage() {
|
||||
const { data: groupsData, isLoading: isLoadingGroups } = useQuery<any>({
|
||||
queryKey: ['/api/group-dashboard-data'],
|
||||
queryFn: async () => {
|
||||
const response = await fetch('/api/ad/groups?properties=name,description,whenCreated,member,memberOf');
|
||||
const response = await fetch('/api/group-dashboard-data');
|
||||
if (!response.ok) throw new Error('Failed to fetch groups');
|
||||
const groups = await response.json();
|
||||
|
||||
// Get the structure of the data to determine field types
|
||||
const fields = getFieldTypes(groups.data || []);
|
||||
const groupData = groups.data || [];
|
||||
const fields = getFieldTypes(groupData);
|
||||
|
||||
console.log('Group data fields:', fields);
|
||||
|
||||
return {
|
||||
id: 'groups',
|
||||
name: 'Active Directory Groups',
|
||||
data: groups.data || [],
|
||||
data: groupData,
|
||||
fields,
|
||||
};
|
||||
},
|
||||
|
||||
+5
-5
@@ -5090,19 +5090,19 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
const connectionId = connections[0].id;
|
||||
|
||||
// Get counts from all AD objects
|
||||
const usersCount = await db.select({ count: sql`count(*)` }).from(adUsers)
|
||||
const usersCount = await db.select({ count: count() }).from(adUsers)
|
||||
.where(eq(adUsers.connectionId, connectionId));
|
||||
|
||||
const computersCount = await db.select({ count: sql`count(*)` }).from(adComputers)
|
||||
const computersCount = await db.select({ count: count() }).from(adComputers)
|
||||
.where(eq(adComputers.connectionId, connectionId));
|
||||
|
||||
const groupsCount = await db.select({ count: sql`count(*)` }).from(adGroups)
|
||||
const groupsCount = await db.select({ count: count() }).from(adGroups)
|
||||
.where(eq(adGroups.connectionId, connectionId));
|
||||
|
||||
const sitesCount = await db.select({ count: sql`count(*)` }).from(adSites)
|
||||
const sitesCount = await db.select({ count: count() }).from(adSites)
|
||||
.where(eq(adSites.connectionId, connectionId));
|
||||
|
||||
const domainsCount = await db.select({ count: sql`count(*)` }).from(adDomains)
|
||||
const domainsCount = await db.select({ count: count() }).from(adDomains)
|
||||
.where(eq(adDomains.connectionId, connectionId));
|
||||
|
||||
// Return the counts
|
||||
|
||||
Reference in New Issue
Block a user