Skip to content

Commit

Permalink
Dependency Graph Backend (#883)
Browse files Browse the repository at this point in the history
* feat: initial commit
* feat: added dependency graph supoort for ec2 and eip
* feat: fixed migration changes
  • Loading branch information
AvineshTripathi committed Jul 15, 2023
1 parent 55a8e7c commit c056593
Show file tree
Hide file tree
Showing 29 changed files with 1,211 additions and 261 deletions.
26 changes: 26 additions & 0 deletions dashboard/components/explorer/dependency-graph/dependencygraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import DependencyGraphError from './dependencygrapherror';
import DependencyGraphSkeleton from './dependencygraphskeleton';
import DependencyGraphView from './dependencygrapview';
import { ReactFlowData } from './hooks/useDependencyGraph';

export type DashboardDependencyGraphProps = {
loading: boolean;
data: ReactFlowData | undefined;
error: boolean;
fetch: () => void;
};

function DependencyGraph({
loading,
data,
error,
fetch
}: DashboardDependencyGraphProps) {
if (loading) return <DependencyGraphSkeleton />;

if (error) return <DependencyGraphError fetch={fetch} />;

return <DependencyGraphView data={data} />;
}

export default DependencyGraph;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Button from '../../button/Button';

type DashboardDependencyGraphErrorProps = {
fetch: () => void;
};

function DependencyGraphError({ fetch }: DashboardDependencyGraphErrorProps) {
return (
<>
<div className={`w-full rounded-lg bg-white px-6 py-4 pb-6`}>
<div className="-mx-6 flex items-center justify-between border-b border-black-200/40 px-6 pb-4">
<div>
<p className="text-sm font-semibold text-black-900">
Dependency Graph
</p>
<div className="mt-1"></div>
<p className="text-xs text-black-300">
Analyze account resource associations
</p>
</div>
<div className="flex h-[60px] items-center"></div>
</div>
<div className="mt-8"></div>
<div className="flex flex-col items-center justify-center">
<svg
className="h-20 w-20"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
viewBox="0 0 24 24"
>
<path stroke="none" d="M0 0h24v24H0z" />
<path d="M4 8V6a2 2 0 012-2h2M4 16v2a2 2 0 002 2h2M16 4h2a2 2 0 012 2v2M16 20h2a2 2 0 002-2v-2M9 10h.01M15 10h.01M9.5 15.05a3.5 3.5 0 015 0" />
</svg>
<p className="text-sm font-semibold text-black-900">
Cannot fetch Relationships
</p>
<div className="m-2 flex-shrink-0">
<Button style="secondary" size="sm" onClick={fetch}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 12c0 5.52-4.48 10-10 10s-8.89-5.56-8.89-5.56m0 0h4.52m-4.52 0v5M2 12C2 6.48 6.44 2 12 2c6.67 0 10 5.56 10 5.56m0 0v-5m0 5h-4.44"
></path>
</svg>
Try again
</Button>
</div>
</div>
<div className="mt-12"></div>
</div>
</>
);
}

export default DependencyGraphError;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function DependencyGraphSkeleton() {
return (
<>
<div
data-testid="loading"
className="min-h-[396px] w-full animate-pulse rounded-lg bg-white px-6 py-4 pb-6"
>
<div className="-mx-6 flex items-center justify-between border-b border-black-200/40 px-6 pb-4">
<div>
<div className="h-3 w-24 rounded-lg bg-komiser-200/50"></div>
<div className="mt-2"></div>
<div className="h-3 w-48 rounded-lg bg-komiser-200/50"></div>
</div>
<div className="h-[60px]"></div>
</div>
<div className="mt-8"></div>
<div className="h-screen">{/* TODO - Add Skeleton Grpah */}</div>
<div className="mt-12"></div>
</div>
</>
);
}

export default DependencyGraphSkeleton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import DependencyGraph from './dependencygraph';
import useDependencyGraph from './hooks/useDependencyGraph';

function DependencyGraphWrapper() {
const { loading, data, error, fetch } = useDependencyGraph();
return (
<>
<div className="flex flex-col gap-6">
<p className="flex items-center gap-2 text-lg font-medium text-black-900">
Graph View
</p>
<DependencyGraph
loading={loading}
data={data}
error={error}
fetch={fetch}
/>
</div>
</>
);
}

export default DependencyGraphWrapper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'reactflow/dist/style.css';
import CustomNode from './nodes/nodes';
import { ReactFlowData } from './hooks/useDependencyGraph';

const nodeTypes = {
customNode: CustomNode
};

export type DashboardDependencyGraphViewProps = {
data: ReactFlowData | undefined;
};

function DependencyGraphView({ data }: DashboardDependencyGraphViewProps) {
return (
<div className={`w-full rounded-lg bg-white px-6 py-4 pb-6`}>
<div className="-mx-6 flex items-center justify-between border-b border-black-200/40 px-6 pb-4">
<div>
<p className="text-sm font-semibold text-black-900">
Dependency Graph
</p>
<div className="mt-1"></div>
<p className="text-xs text-black-300">
Analyze account resource associations
</p>
</div>
<div className="flex h-[60px] items-center"></div>
</div>
<div className="mt-8"></div>
<div className="h-[70vh]">{/* TODO - Add Graph */}</div>
<div className="flex gap-4 text-xs text-black-300"></div>
</div>
);
}

export default DependencyGraphView;
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useEffect, useState } from 'react';
import settingsService from '../../../../services/settingsService';

export type ReactFlowData = {
nodes: any[];
edges: any[];
};

// converting the json object into data that reactflow needs
// TODO - based on selected library
function GetData(res: any) {
const d = {
nodes: [],
edges: []
} as ReactFlowData;
res.forEach((ele: any) => {
// check if node exist already
if (d.nodes.findIndex(element => element.id === ele.resourceId) === -1) {
const a = {
id: ele.resourceId,
type: 'customNode',
data: { label: ele.service, resource: 'AWS' },
position: { x: 0, y: 0 }
};
d.nodes.push(a);
}
ele.relations.forEach((rel: any) => {
// check for other node exists
if (d.nodes.findIndex(element => element.id === rel.ResourceID) === -1) {
const a = {
id: rel.ResourceID,
type: 'customNode',
data: { label: rel.Type, resource: 'AWS' }, // when supporting new provider this could be made dynamic
position: { x: 0, y: 0 }
};
d.nodes.push(a);
}
const edge = {
id: `${ele.resourceId}-${rel.ResourceID}`,
source: ele.resourceId,
target: rel.ResourceID
};
d.edges.push(edge);
});
});
return d;
}

function useDependencyGraph() {
const [loading, setLoading] = useState(true);
const [data, setData] = useState<ReactFlowData>();
const [error, setError] = useState(false);

function fetch() {
if (!loading) {
setLoading(true);
}

if (error) {
setError(false);
}

settingsService.getRelations().then(res => {
if (res === Error) {
setLoading(false);
setError(true);
} else {
setLoading(false);
setData(GetData(res));
}
});
}

useEffect(() => {
fetch();
}, []);

return { loading, data, error, fetch };
}

export default useDependencyGraph;
54 changes: 54 additions & 0 deletions dashboard/components/explorer/dependency-graph/nodes/nodes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { Handle, Position } from 'reactflow';
import Tippy from '@tippyjs/react';

type CircleNodeProps = {
data: any;
id: string;
};

function getInfo(data: any, id: any) {
return (
<>
<div className="h-auto w-auto border bg-white">
<div className="m-4">
<p>Name: {data.label}</p>
<p>ResourceId: {id}</p>
</div>
</div>
</>
);
}

function getLogo(resource: string) {
switch (resource) {
case 'AWS':
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
<path d="M180.41 203.01c-.72 22.65 10.6 32.68 10.88 39.05a8.164 8.164 0 0 1-4.1 6.27l-12.8 8.96a10.66 10.66 0 0 1-5.63 1.92c-.43-.02-8.19 1.83-20.48-25.61a78.608 78.608 0 0 1-62.61 29.45c-16.28.89-60.4-9.24-58.13-56.21-1.59-38.28 34.06-62.06 70.93-60.05 7.1.02 21.6.37 46.99 6.27v-15.62c2.69-26.46-14.7-46.99-44.81-43.91-2.4.01-19.4-.5-45.84 10.11-7.36 3.38-8.3 2.82-10.75 2.82-7.41 0-4.36-21.48-2.94-24.2 5.21-6.4 35.86-18.35 65.94-18.18a76.857 76.857 0 0 1 55.69 17.28 70.285 70.285 0 0 1 17.67 52.36l-.01 69.29zM93.99 235.4c32.43-.47 46.16-19.97 49.29-30.47 2.46-10.05 2.05-16.41 2.05-27.4-9.67-2.32-23.59-4.85-39.56-4.87-15.15-1.14-42.82 5.63-41.74 32.26-1.24 16.79 11.12 31.4 29.96 30.48zm170.92 23.05c-7.86.72-11.52-4.86-12.68-10.37l-49.8-164.65c-.97-2.78-1.61-5.65-1.92-8.58a4.61 4.61 0 0 1 3.86-5.25c.24-.04-2.13 0 22.25 0 8.78-.88 11.64 6.03 12.55 10.37l35.72 140.83 33.16-140.83c.53-3.22 2.94-11.07 12.8-10.24h17.16c2.17-.18 11.11-.5 12.68 10.37l33.42 142.63L420.98 80.1c.48-2.18 2.72-11.37 12.68-10.37h19.72c.85-.13 6.15-.81 5.25 8.58-.43 1.85 3.41-10.66-52.75 169.9-1.15 5.51-4.82 11.09-12.68 10.37h-18.69c-10.94 1.15-12.51-9.66-12.68-10.75L328.67 110.7l-32.78 136.99c-.16 1.09-1.73 11.9-12.68 10.75h-18.3zm273.48 5.63c-5.88.01-33.92-.3-57.36-12.29a12.802 12.802 0 0 1-7.81-11.91v-10.75c0-8.45 6.2-6.9 8.83-5.89 10.04 4.06 16.48 7.14 28.81 9.6 36.65 7.53 52.77-2.3 56.72-4.48 13.15-7.81 14.19-25.68 5.25-34.95-10.48-8.79-15.48-9.12-53.13-21-4.64-1.29-43.7-13.61-43.79-52.36-.61-28.24 25.05-56.18 69.52-55.95 12.67-.01 46.43 4.13 55.57 15.62 1.35 2.09 2.02 4.55 1.92 7.04v10.11c0 4.44-1.62 6.66-4.87 6.66-7.71-.86-21.39-11.17-49.16-10.75-6.89-.36-39.89.91-38.41 24.97-.43 18.96 26.61 26.07 29.7 26.89 36.46 10.97 48.65 12.79 63.12 29.58 17.14 22.25 7.9 48.3 4.35 55.44-19.08 37.49-68.42 34.44-69.26 34.42zm40.2 104.86c-70.03 51.72-171.69 79.25-258.49 79.25A469.127 469.127 0 0 1 2.83 327.46c-6.53-5.89-.77-13.96 7.17-9.47a637.37 637.37 0 0 0 316.88 84.12 630.22 630.22 0 0 0 241.59-49.55c11.78-5 21.77 7.8 10.12 16.38zm29.19-33.29c-8.96-11.52-59.28-5.38-81.81-2.69-6.79.77-7.94-5.12-1.79-9.47 40.07-28.17 105.88-20.1 113.44-10.63 7.55 9.47-2.05 75.41-39.56 106.91-5.76 4.87-11.27 2.3-8.71-4.1 8.44-21.25 27.39-68.49 18.43-80.02z" />
</svg>
);
default:
return <></>;
}
}

const css = `
.c {
border: 1px solid black;
}
`;
const CustomNode: React.FC<CircleNodeProps> = ({ data, id }) => (
<>
<style>{css}</style>
<Tippy content={<>{getInfo(data, id)}</>}>
<div className="c flex h-24 w-24 items-center justify-center rounded-[20%] border p-6">
<Handle type="target" position={Position.Top} id={`${id}.top`} />
<Handle type="source" position={Position.Bottom} id={`${id}.bottom`} />
{getLogo(data.resource)}
</div>
</Tippy>
</>
);

export default CustomNode;
3 changes: 2 additions & 1 deletion dashboard/components/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ function Navbar() {
const router = useRouter();
const nav = [
{ label: 'Dashboard', href: '/dashboard' },
{ label: 'Inventory', href: '/inventory' }
{ label: 'Inventory', href: '/inventory' },
{ label: 'Explorer', href: '/explorer' }
];
return (
<nav
Expand Down
Loading

0 comments on commit c056593

Please sign in to comment.