Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 8 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['tsconfig.json', 'apps/dashboard/tsconfig.json'],
project: ['tsconfig.json'],
tsconfigRootDir: __dirname,
sourceType: 'module',
},
Expand All @@ -12,7 +12,13 @@ module.exports = {
],
root: true,
env: { node: true },
ignorePatterns: ['.eslintrc.js', 'dist/**'],
// Exclude the Next.js dashboard app entirely — it uses its own tsconfig/eslint
// and its files are not included in the root tsconfig project references.
ignorePatterns: [
'.eslintrc.js',
'dist/**',
'apps/dashboard/**',
],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
dist/
node_modules/
coverage/
.next/
apps/dashboard/.next/
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
4 changes: 2 additions & 2 deletions apps/backend/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"outDir": "./dist",
"baseUrl": "./src",
"types": ["node"],
"paths": {
"@common/*": ["../../../apps/backend/src/common/*"],
"@modules/*": ["../../../apps/backend/src/modules/*"],
Expand All @@ -17,4 +17,4 @@
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.spec.ts"]
}
}
25 changes: 25 additions & 0 deletions apps/dashboard/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": null,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": ["@typescript-eslint"],
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
"env": {
"browser": true,
"es2021": true,
"node": true
},
"rules": {
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off"
},
"ignorePatterns": ["node_modules/", ".next/", "dist/"]
}
7 changes: 7 additions & 0 deletions apps/dashboard/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
reactStrictMode: true,
};

export default nextConfig;
25 changes: 25 additions & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@sentinel/dashboard",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --port 3001",
"build": "next build",
"start": "next start --port 3001",
"lint": "next lint"
},
"dependencies": {
"next": "14.2.29",
"react": "^19.2.7",
"react-dom": "^19.2.7"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.0.0",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3"
}
}
6 changes: 6 additions & 0 deletions apps/dashboard/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
54 changes: 54 additions & 0 deletions apps/dashboard/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

body {
@apply bg-gray-950 text-gray-100;
}

/* Scrollbar styling */
::-webkit-scrollbar {
@apply w-1.5 h-1.5;
}
::-webkit-scrollbar-track {
@apply bg-gray-900;
}
::-webkit-scrollbar-thumb {
@apply bg-gray-700 rounded-full;
}
::-webkit-scrollbar-thumb:hover {
@apply bg-gray-600;
}
}

@layer components {
.sentinel-card {
@apply bg-gray-900 border border-gray-800 rounded-xl p-6;
}

.sentinel-badge {
@apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium;
}

.sentinel-badge--critical {
@apply bg-red-950 text-red-400 border border-red-800;
}

.sentinel-badge--high {
@apply bg-orange-950 text-orange-400 border border-orange-800;
}

.sentinel-badge--medium {
@apply bg-yellow-950 text-yellow-400 border border-yellow-800;
}

.sentinel-badge--low {
@apply bg-blue-950 text-blue-400 border border-blue-800;
}
}
43 changes: 43 additions & 0 deletions apps/dashboard/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Metadata } from 'next';
import './globals.css';
import { Sidebar } from '@/components/layout/Sidebar';
import { TopBar } from '@/components/layout/TopBar';

export const metadata: Metadata = {
title: {
default: 'Sentinel Dashboard',
template: '%s | Sentinel',
},
description: 'Real-time monitoring and security alerts for Stellar/EVM smart contracts.',
icons: {
icon: '/favicon.ico',
},
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" className="h-full">
<body className="h-full flex overflow-hidden">
{/* Sidebar */}
<Sidebar />

{/* Main content area */}
<div className="flex-1 flex flex-col min-w-0 overflow-hidden">
<TopBar />
<main
id="main-content"
className="flex-1 overflow-y-auto p-6 space-y-6"
role="main"
aria-label="Dashboard content"
>
{children}
</main>
</div>
</body>
</html>
);
}
40 changes: 40 additions & 0 deletions apps/dashboard/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { Metadata } from 'next';
import { KpiCard } from '@/components/dashboard/KpiCard';
import { AlertHistoryTable } from '@/components/dashboard/AlertHistoryTable';
import { SecurityReportingDashboard } from '@/components/dashboard/SecurityReportingDashboard';

export const metadata: Metadata = {
title: 'Overview',
};

export default function DashboardPage() {
return (
<div className="space-y-6">
{/* Page heading */}
<div>
<h1 className="text-2xl font-semibold text-white">Overview</h1>
<p className="mt-1 text-sm text-gray-400">
Real-time monitoring across Stellar/EVM networks
</p>
</div>

{/* KPI row */}
<section aria-label="Key metrics" className="grid grid-cols-2 gap-4 lg:grid-cols-4">
<KpiCard label="Total Alerts" value={27} trend="+3 today" variant="default" />
<KpiCard label="Critical Unresolved" value={2} trend="Needs attention" variant="danger" />
<KpiCard label="Resolved" value={20} trend="74% resolution rate" variant="success" />
<KpiCard label="Monitored Contracts" value={14} trend="Across 3 chains" variant="info" />
</section>

{/* Alert history */}
<section aria-label="Alert history">
<AlertHistoryTable />
</section>

{/* Security report */}
<section aria-label="Security report">
<SecurityReportingDashboard />
</section>
</div>
);
}
Loading
Loading