Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency graph another attempt #883

Merged
merged 8 commits into from
Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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