diff --git a/dashboard/components/explorer/dependency-graph/dependencygraph.tsx b/dashboard/components/explorer/dependency-graph/dependencygraph.tsx
new file mode 100644
index 000000000..42e3cdaf2
--- /dev/null
+++ b/dashboard/components/explorer/dependency-graph/dependencygraph.tsx
@@ -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 ;
+
+ if (error) return ;
+
+ return ;
+}
+
+export default DependencyGraph;
diff --git a/dashboard/components/explorer/dependency-graph/dependencygrapherror.tsx b/dashboard/components/explorer/dependency-graph/dependencygrapherror.tsx
new file mode 100644
index 000000000..1bbe0e785
--- /dev/null
+++ b/dashboard/components/explorer/dependency-graph/dependencygrapherror.tsx
@@ -0,0 +1,67 @@
+import Button from '../../button/Button';
+
+type DashboardDependencyGraphErrorProps = {
+ fetch: () => void;
+};
+
+function DependencyGraphError({ fetch }: DashboardDependencyGraphErrorProps) {
+ return (
+ <>
+
+
+
+
+ Dependency Graph
+
+
+
+ Analyze account resource associations
+
+
+
+
+
+
+
+
+ Cannot fetch Relationships
+
+
+
+
+
+ >
+ );
+}
+
+export default DependencyGraphError;
diff --git a/dashboard/components/explorer/dependency-graph/dependencygraphskeleton.tsx b/dashboard/components/explorer/dependency-graph/dependencygraphskeleton.tsx
new file mode 100644
index 000000000..dc3ee3531
--- /dev/null
+++ b/dashboard/components/explorer/dependency-graph/dependencygraphskeleton.tsx
@@ -0,0 +1,24 @@
+function DependencyGraphSkeleton() {
+ return (
+ <>
+
+
+
+
{/* TODO - Add Skeleton Grpah */}
+
+
+ >
+ );
+}
+
+export default DependencyGraphSkeleton;
diff --git a/dashboard/components/explorer/dependency-graph/dependencygraphwrapper.tsx b/dashboard/components/explorer/dependency-graph/dependencygraphwrapper.tsx
new file mode 100644
index 000000000..2412a29c2
--- /dev/null
+++ b/dashboard/components/explorer/dependency-graph/dependencygraphwrapper.tsx
@@ -0,0 +1,23 @@
+import DependencyGraph from './dependencygraph';
+import useDependencyGraph from './hooks/useDependencyGraph';
+
+function DependencyGraphWrapper() {
+ const { loading, data, error, fetch } = useDependencyGraph();
+ return (
+ <>
+
+ >
+ );
+}
+
+export default DependencyGraphWrapper;
diff --git a/dashboard/components/explorer/dependency-graph/dependencygrapview.tsx b/dashboard/components/explorer/dependency-graph/dependencygrapview.tsx
new file mode 100644
index 000000000..18497d98a
--- /dev/null
+++ b/dashboard/components/explorer/dependency-graph/dependencygrapview.tsx
@@ -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 (
+
+
+
+
+ Dependency Graph
+
+
+
+ Analyze account resource associations
+
+
+
+
+
+
{/* TODO - Add Graph */}
+
+
+ );
+}
+
+export default DependencyGraphView;
diff --git a/dashboard/components/explorer/dependency-graph/hooks/useDependencyGraph.tsx b/dashboard/components/explorer/dependency-graph/hooks/useDependencyGraph.tsx
new file mode 100644
index 000000000..ed2a066cf
--- /dev/null
+++ b/dashboard/components/explorer/dependency-graph/hooks/useDependencyGraph.tsx
@@ -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();
+ 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;
diff --git a/dashboard/components/explorer/dependency-graph/nodes/nodes.tsx b/dashboard/components/explorer/dependency-graph/nodes/nodes.tsx
new file mode 100644
index 000000000..8b5e861ea
--- /dev/null
+++ b/dashboard/components/explorer/dependency-graph/nodes/nodes.tsx
@@ -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 (
+ <>
+
+
+
Name: {data.label}
+
ResourceId: {id}
+
+
+ >
+ );
+}
+
+function getLogo(resource: string) {
+ switch (resource) {
+ case 'AWS':
+ return (
+
+ );
+ default:
+ return <>>;
+ }
+}
+
+const css = `
+ .c {
+ border: 1px solid black;
+ }
+`;
+const CustomNode: React.FC = ({ data, id }) => (
+ <>
+
+ {getInfo(data, id)}>}>
+
+
+
+ {getLogo(data.resource)}
+
+
+ >
+);
+
+export default CustomNode;
diff --git a/dashboard/components/navbar/Navbar.tsx b/dashboard/components/navbar/Navbar.tsx
index 1de7c18e1..01a71ae0a 100644
--- a/dashboard/components/navbar/Navbar.tsx
+++ b/dashboard/components/navbar/Navbar.tsx
@@ -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 (