Skip to content

Commit

Permalink
fix(dashboard): Add service chart
Browse files Browse the repository at this point in the history
  • Loading branch information
cmp5987 committed Mar 17, 2024
1 parent 031684a commit 5366207
Show file tree
Hide file tree
Showing 17 changed files with 112 additions and 201 deletions.
12 changes: 6 additions & 6 deletions tavern/internal/www/build/asset-manifest.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions tavern/internal/www/build/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions tavern/internal/www/build/static/css/main.354fb8c2.css

This file was deleted.

1 change: 0 additions & 1 deletion tavern/internal/www/build/static/css/main.354fb8c2.css.map

This file was deleted.

4 changes: 4 additions & 0 deletions tavern/internal/www/build/static/css/main.d7470eb8.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tavern/internal/www/build/static/css/main.d7470eb8.css.map

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions tavern/internal/www/build/static/js/main.bf838c24.js

This file was deleted.

3 changes: 3 additions & 0 deletions tavern/internal/www/build/static/js/main.f1386e50.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions tavern/internal/www/build/static/js/main.f72f0877.js

This file was deleted.

125 changes: 0 additions & 125 deletions tavern/internal/www/build/static/js/main.f72f0877.js.LICENSE.txt

This file was deleted.

1 change: 0 additions & 1 deletion tavern/internal/www/build/static/js/main.f72f0877.js.map

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from "react";
import DashboardStatistic from "./DashboardStatistic";

import GroupBarChart from "./GroupBarChart";
import TomeBarChart from "./TomeBarChart";
import TagBarChart from "./TagBarChart";
import TargetReccomendation from "./TargetRecommendation";

const EnvironmentCard = ({ formattedData, hosts, loading }: { formattedData: any, hosts: Array<any>, loading: boolean }) => {

Expand All @@ -13,13 +14,26 @@ const EnvironmentCard = ({ formattedData, hosts, loading }: { formattedData: any
</h3>
<div className="col-span-1 flex flex-row md:flex-col gap-4 flex-wrap">
<DashboardStatistic label="Total groups" value={formattedData?.groupUsage?.length} loading={loading} />
<DashboardStatistic label="Total services" value={formattedData?.serviceUsage.length} loading={loading} />
<DashboardStatistic label="Unique tomes run" value={formattedData?.tomeUsage?.length} loading={loading} />
</div>
<div className="col-span-1 md:col-span-2 ">
<GroupBarChart data={formattedData?.groupUsage || []} loading={loading} hosts={hosts} />
</div>
<div className="col-span-1 md:col-span-2">
<TomeBarChart data={formattedData?.tomeUsage || []} loading={loading} />
<div className="col-span-4 grid grid-cols-4 gap-4">
<div className="col-span-2">
<TagBarChart data={formattedData?.groupUsage || []} loading={loading} tagKind="group">
<TargetReccomendation data={formattedData?.groupUsage || []} tagKind="group" hosts={hosts} />
</TagBarChart>
</div>
<div className="col-span-2">
<TagBarChart data={formattedData?.serviceUsage || []} loading={loading} tagKind="service">
<TargetReccomendation data={formattedData?.serviceUsage || []} tagKind="service" hosts={hosts} />
</TagBarChart>
</div>
<div className="col-span-4">
<TomeBarChart data={formattedData?.tomeUsage || []} loading={loading} />
</div>
<div className="col-span-2">

</div>
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,27 @@ import { useNavigate } from 'react-router-dom';
import { BarChart, Bar, Rectangle, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, Cell } from 'recharts';

import { EmptyState, EmptyStateType } from '../../../components/tavern-base-ui/EmptyState';
import { TomeTag } from '../../../utils/consts';
import { TaskChartKeys } from '../../../utils/enums';
import { getOfflineOnlineStatus } from '../../../utils/utils';
import Button from '../../../components/tavern-base-ui/button/Button';


const GroupBarChart = ({ data, loading, hosts }: { data: Array<any>, loading: boolean, hosts: Array<any> }) => {
const TagBarChart = ({ data, loading, tagKind, children }: { data: Array<any>, loading: boolean, tagKind: string, children?: React.ReactNode }) => {
const navigation = useNavigate();

if (loading) {
return <EmptyState type={EmptyStateType.loading} label="Formatting group data..." />
}

const height = data.length * 40 < 320 ? 320 : data.length * 40;
const groupWithFewestTasks = data.length > 0 ? data.find((task: any) => task.name !== "undefined") : null;

const getTotalActiveBeaconsForGroup = () => {
const returnedValue = hosts.reduce((acc, curr) => {
const matchesGroup = curr?.tags.find((tag: TomeTag) => { return tag.name === groupWithFewestTasks.name });
const beaconStatus = getOfflineOnlineStatus(curr.beacons || [])
if (matchesGroup) {
return acc += beaconStatus.online;
}
return acc;
}, 0);
return returnedValue;
};

const handleClickQuestDetails = (item: any) => {
navigation("/tasks", {
state: [{
'label': item?.name,
'kind': 'group',
'name': item?.name,
'value': item?.id
}]
})
}

const handleBarClick = (_: any, index?: any) => {
const item = data[index];
if (item.name === "undefined") {
return null;
}
navigation("/tasks", {
navigation("/quests", {
state: [{
'label': item?.name,
'kind': 'group',
'kind': tagKind,
'name': item?.name,
'value': item?.id
}]
Expand All @@ -60,7 +33,7 @@ const GroupBarChart = ({ data, loading, hosts }: { data: Array<any>, loading: bo
return (
<div className=" flex flex-col gap-6 w-full h-full">
<div className='flex flex-row gap-4 items-center'>
<h2 className="text-lg">Tasks by group</h2>
<h2 className="text-lg">Quest tasks by {tagKind}</h2>
</div>
<div className='max-h-56 overflow-y-scroll'>
<div style={{ height: `${height}px` }}>
Expand Down Expand Up @@ -106,24 +79,8 @@ const GroupBarChart = ({ data, loading, hosts }: { data: Array<any>, loading: bo
</ResponsiveContainer>
</div>
</div>
{groupWithFewestTasks &&
<div className='flex flex-col border-l-4 border-purple-900 px-4 py-2 rounded'>
<h4 className="font-semibold text-gray-900">Consider targeting the group with fewest tasks</h4>
<p className='text-sm'>{groupWithFewestTasks.name} has {groupWithFewestTasks[TaskChartKeys.taskNoError]} task run and {getTotalActiveBeaconsForGroup()} online beacons</p>
<div className='flex flex-row gap-4 mt-2'>
<Button
buttonStyle={{ color: "purple", size: "xs", vPadding: "none", xPadding: "none" }}
buttonVariant='ghost'
className='hover:underline hover:bg-white'
onClick={() => {
handleClickQuestDetails(groupWithFewestTasks)
}}>
See quest details
</Button>
</div>
</div>
}
{children && children}
</div>
);
}
export default GroupBarChart;
export default TagBarChart;
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { FC } from "react";
import { HostType, TomeTag } from "../../../utils/consts";
import { getOfflineOnlineStatus } from "../../../utils/utils";
import { TaskChartKeys } from "../../../utils/enums";
import Button from "../../../components/tavern-base-ui/button/Button";
import { useNavigate } from "react-router-dom";

type TargetReccomendationProps = {
hosts: Array<HostType>;
data: Array<any>;
tagKind: string;
}

const TargetReccomendation: FC<TargetReccomendationProps> = ({ hosts, data, tagKind }) => {
const navigation = useNavigate();

const tagWithFewestTasks = data.length > 0 ? data.find((task: any) => task.name !== "undefined") : null;

const getTotalActiveBeaconsForTagKind = () => {
const returnedValue = hosts.reduce((acc, curr) => {
const matchesGroup = curr?.tags?.find((tag: TomeTag) => { return tag.name === tagWithFewestTasks.name });
const beaconStatus = getOfflineOnlineStatus(curr.beacons || [])
if (matchesGroup) {
return acc += beaconStatus.online;
}
return acc;
}, 0);
return returnedValue;
};

const handleClickQuestDetails = (item: any) => {
navigation("/quests", {
state: [{
'label': item?.name,
'kind': tagKind,
'name': item?.name,
'value': item?.id
}]
})
}

if (!tagWithFewestTasks) {
return null;
}

return (
<div className='flex flex-col border-l-4 border-purple-900 px-4 py-2 rounded'>
<h4 className="font-semibold text-gray-900">Consider targeting the {tagKind} with fewest tasks</h4>
<p className='text-sm'>{tagWithFewestTasks.name} has {tagWithFewestTasks[TaskChartKeys.taskNoError]} task run and {getTotalActiveBeaconsForTagKind()} online beacons</p>
<div className='flex flex-row gap-4 mt-2'>
<Button
buttonStyle={{ color: "purple", size: "xs", vPadding: "none", xPadding: "none" }}
buttonVariant='ghost'
className='hover:underline hover:bg-'
onClick={() => {
handleClickQuestDetails(tagWithFewestTasks)
}}>
See quest details
</Button>
</div>
</div>
);
}
export default TargetReccomendation;
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const useOverviewData = (data: Array<any>) => {
taskTimeline: [],
taskTactics: [],
groupUsage: [],
serviceUsage: [],
platformUsage: [],
totalQuests: 0,
totalOutput: 0,
totalTasks: 0,
Expand Down Expand Up @@ -118,14 +120,17 @@ export const useOverviewData = (data: Array<any>) => {
const uniqueTomeCount = {} as any;
const uniqueTactics = {} as any;
const uniqueGroup = {} as any;
const uniqueService = {} as any;
const tasksTimeline = [] as Array<any>;
let tasksWithOutput = 0;
let tasksWithError = 0;

for (let index in data){
const groupTag = data[index]?.node?.beacon?.host?.tags.find( (tag: TomeTag) => tag.kind === "group");
const serviceTag = data[index]?.node?.beacon?.host?.tags.find( (tag: TomeTag) => tag.kind === "service");
applyUniqueTermCount(data[index]?.node?.quest?.id, data[index]?.node?.quest?.id, false, uniqueQuestCount);
applyUniqueTermCount(groupTag?.name, groupTag?.id, data[index]?.node?.error.length > 0, uniqueGroup);
applyUniqueTermCount(serviceTag?.name, serviceTag?.id, data[index]?.node?.error.length > 0, uniqueService);
applyUniqueTermCount(data[index]?.node?.quest?.tome?.name, data[index]?.node?.quest?.tome.id, data[index]?.node?.error.length > 0, uniqueTomeCount);
modifyTaskTimeline(data[index], tasksTimeline);
modifyUniqueTactics(data[index], uniqueTactics);
Expand All @@ -140,6 +145,7 @@ export const useOverviewData = (data: Array<any>) => {
taskTimelime: tasksTimeline,
taskTactics: Object.keys(uniqueTactics),
groupUsage: getTermUsage(uniqueGroup, false),
serviceUsage: getTermUsage(uniqueService, false),
totalQuests: Object.keys(uniqueQuestCount).length,
totalOutput: tasksWithOutput,
totalTasks: data.length,
Expand Down

0 comments on commit 5366207

Please sign in to comment.