Skip to content

Commit

Permalink
Devtool tenant onboarding (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
samteb authored Apr 3, 2024
1 parent ebdebbd commit 6a31273
Show file tree
Hide file tree
Showing 54 changed files with 2,586 additions and 298 deletions.
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@fortawesome:registry=https://npm.fontawesome.com/
//npm.fontawesome.com/:_authToken=BB192AC2-6663-4FB6-8C01-F1156629CD1F
Binary file added apps/devtool/public/narval-wordmark-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
209 changes: 209 additions & 0 deletions apps/devtool/src/app/_components/HealthcheckStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
'use client'

import axios from 'axios'
import { useEffect, useState } from 'react'
import useStore from '../_hooks/useStore'
import { classNames } from '../_lib/utils'

const HealthcheckStatus = () => {
const [status, setStatus] = useState({
engineConnection: false,
engineDataStore: false,
entityDataUrl: false,
policyDataUrl: false,
entitySignatureUrl: false,
policySignatureUrl: false,
vaultConnection: false
})
const {
engineUrl,
engineClientId,
engineClientSecret,
entityDataStoreUrl,
policyDataStoreUrl,
entitySignatureUrl,
policySignatureUrl,
vaultUrl
} = useStore()

const checkPolicyDataConnection = async () => {
try {
await axios.get(policyDataStoreUrl)
setStatus((prev) => ({ ...prev, policyDataUrl: true }))
} catch (e) {
setStatus((prev) => ({ ...prev, policyDataUrl: false }))
}
}

const checkPolicySignatureConnection = async () => {
try {
await axios.get(policySignatureUrl)
setStatus((prev) => ({ ...prev, policySignatureUrl: true }))
} catch (e) {
setStatus((prev) => ({ ...prev, policySignatureUrl: false }))
}
}

const checkEntityDataConnection = async () => {
try {
await axios.get(entityDataStoreUrl)
setStatus((prev) => ({ ...prev, entityDataUrl: true }))
} catch (e) {
setStatus((prev) => ({ ...prev, entityDataUrl: false }))
}
}

const checkEntitySignatureConnection = async () => {
try {
await axios.get(entitySignatureUrl)
setStatus((prev) => ({ ...prev, entitySignatureUrl: true }))
} catch (e) {
setStatus((prev) => ({ ...prev, entitySignatureUrl: false }))
}
}

const checkEngineConnection = async () => {
try {
await axios.get(engineUrl)
setStatus((prev) => ({ ...prev, engineConnection: true }))
} catch (e) {
setStatus((prev) => ({ ...prev, engineConnection: false }))
}
}

const checkEngineDataStore = async () => {
try {
await axios.post(`${engineUrl}/clients/sync`, null, {
headers: {
'x-client-id': engineClientId,
'x-client-secret': engineClientSecret
}
})
setStatus((prev) => ({ ...prev, engineDataStore: true }))
} catch (e) {
setStatus((prev) => ({ ...prev, engineDataStore: false }))
}
}

const checkVaultConnection = async () => {
try {
await axios.get(vaultUrl)
setStatus((prev) => ({ ...prev, vaultConnection: true }))
} catch (e) {
setStatus((prev) => ({ ...prev, vaultConnection: false }))
}
}

useEffect(() => {
checkPolicyDataConnection()
checkPolicySignatureConnection()
checkEntityDataConnection()
checkEntitySignatureConnection()
checkEngineConnection()
checkEngineDataStore()
checkVaultConnection()
}, [])

return (
<div className="flex flex-col gap-12">
<div className="text-nv-2xl">Healthcheck Status</div>
<div className="flex gap-24">
<div className="flex flex-col gap-4">
<div className="text-nv-xl">Policy Engine</div>
<div className="flex flex-col gap-2">
<div className="text-nv-md underline">Connection</div>
<div className="flex items-center gap-4">
<div
className={classNames(
'h-3 w-3 rounded-full',
status.engineConnection ? 'bg-nv-green-500' : 'bg-nv-red-500'
)}
></div>
<div>{status.engineConnection ? 'Connected' : 'Disconnected'}</div>
</div>
</div>
<div className="flex flex-col gap-2">
<div className="text-nv-md underline">Data Store</div>
<div className="flex items-center gap-4">
<div
className={classNames(
'h-3 w-3 rounded-full',
status.engineDataStore ? 'bg-nv-green-500' : 'bg-nv-red-500'
)}
></div>
<div>{status.engineDataStore ? 'Synced' : 'Unsynced'}</div>
</div>
</div>
</div>
<div className="flex flex-col gap-4">
<div className="text-nv-xl">Vault</div>
<div className="flex flex-col gap-2">
<div className="text-nv-md underline">Connection</div>
<div className="flex items-center gap-4">
<div
className={classNames(
'h-3 w-3 rounded-full',
status.vaultConnection ? 'bg-nv-green-500' : 'bg-nv-red-500'
)}
></div>
<div>{status.vaultConnection ? 'Connected' : 'Disconnected'}</div>
</div>
</div>
</div>
<div className="flex flex-col gap-4">
<div className="text-nv-xl">Data Store</div>
<div className="flex flex-col gap-2">
<div className="text-nv-md underline">Entity Data URL</div>
<div className="flex items-center gap-4">
<div
className={classNames(
'h-3 w-3 rounded-full',
status.entityDataUrl ? 'bg-nv-green-500' : 'bg-nv-red-500'
)}
></div>
<div>{status.entityDataUrl ? 'Connected' : 'Disconnected'}</div>
</div>
</div>
<div className="flex flex-col gap-2">
<div className="text-nv-md underline">Entity Signature URL</div>
<div className="flex items-center gap-4">
<div
className={classNames(
'h-3 w-3 rounded-full',
status.entitySignatureUrl ? 'bg-nv-green-500' : 'bg-nv-red-500'
)}
></div>
<div>{status.entitySignatureUrl ? 'Connected' : 'Disconnected'}</div>
</div>
</div>
<div className="flex flex-col gap-2">
<div className="text-nv-md underline">Policy Data URL</div>
<div className="flex items-center gap-4">
<div
className={classNames(
'h-3 w-3 rounded-full',
status.policyDataUrl ? 'bg-nv-green-500' : 'bg-nv-red-500'
)}
></div>
<div>{status.policyDataUrl ? 'Connected' : 'Disconnected'}</div>
</div>
</div>
<div className="flex flex-col gap-2">
<div className="text-nv-md underline">Policy Signature URL</div>
<div className="flex items-center gap-4">
<div
className={classNames(
'h-3 w-3 rounded-full',
status.policySignatureUrl ? 'bg-nv-green-500' : 'bg-nv-red-500'
)}
></div>
<div>{status.policySignatureUrl ? 'Connected' : 'Disconnected'}</div>
</div>
</div>
</div>
</div>
</div>
)
}

export default HealthcheckStatus
26 changes: 26 additions & 0 deletions apps/devtool/src/app/_components/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use client'

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactNode } from 'react'
import { WagmiProvider } from 'wagmi'
import { config } from '../_lib/config'
import NavBar from './NavBar'

const MainLayout = ({ children }: { children: ReactNode }) => {
const queryClient = new QueryClient()

return (
<div className="h-screen w-screen">
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<NavBar />
<div className="h-full w-full pt-[72px]">
<div className="px-[48px] py-[36px]">{children}</div>
</div>
</QueryClientProvider>
</WagmiProvider>
</div>
)
}

export default MainLayout
60 changes: 60 additions & 0 deletions apps/devtool/src/app/_components/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client'

import Image from 'next/image'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { useAccount, useConnect, useDisconnect } from 'wagmi'
import NarButton from '../_design-system/NarButton'

const NavBar = () => {
const currentPath = usePathname()
const account = useAccount()
const { connectors, connect } = useConnect()
const { disconnect } = useDisconnect()

return (
<nav className="fixed top-0 left-0 z-40 h-[72px] w-full bg-nv-neutrals-900 border-b border-b-nv-neutrals-400">
<div className="flex gap-[32px] items-center justify-end shrink-0 h-full px-[48px]">
<div className="flex items-center gap-2">
<Link href="/">
<Image src="/narval-wordmark-white.png" width="150" height="50" alt="Narval Logo" priority />
</Link>
<div className="flex gap-8 ml-10 text-nv-lg">
<Link href="/policy-engine" className={`${currentPath === '/policy-engine' ? 'underline' : ''}`}>
Policy Engine
</Link>
<Link href="/vault" className={`${currentPath === '/vault' ? 'underline' : ''}`}>
Vault
</Link>
<Link href="/data-store" className={`${currentPath === '/data-store' ? 'underline' : ''}`}>
Data Store
</Link>
<Link
href="/transaction-request"
className={`${currentPath === '/transaction-request' ? 'underline' : ''}`}
>
Transaction Request
</Link>
</div>
</div>
<div className="flex flex-row-reverse gap-2 flex-1">
{!account.isConnected && (
<div className="flex gap-2">
{connectors.map((connector) => (
<NarButton
label=" Connect Wallet"
variant="primary"
key={connector.uid}
onClick={() => connect({ connector })}
/>
))}
</div>
)}
{account.isConnected && <NarButton label="Disconnect" variant="secondary" onClick={() => disconnect()} />}
</div>
</div>
</nav>
)
}

export default NavBar
Loading

0 comments on commit 6a31273

Please sign in to comment.