style(headers): update all page header titles and add HelpTrigger buttons matching demoplace.my.id

This commit is contained in:
rafif committed 2026-07-21 14:06:37 +07:00
1 parent fb75711994
commit 36fe496566
20 files changed
+490 -18

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
const { Client } = require('ssh2');
const remoteScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)';
function scanDir(dir) {
const results = [];
if (!fs.existsSync(dir)) return results;
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const fullPath = path.join(dir, item.name);
if (item.isDirectory()) {
results.push(...scanDir(fullPath));
} else if (item.name.endsWith('.html') || item.name.endsWith('.js')) {
results.push(fullPath);
}
}
return results;
}
console.log('=== AUDITING ALL PAGE HEADERS AND TITLES ON DEMOPLACE.MY.ID ===\\n');
const files = scanDir(root);
files.forEach(file => {
const content = fs.readFileSync(file, 'utf8');
const rel = path.relative(root, file);
// Extract <h2> or <h1> or header titles
const h2s = [];
const h2Match = content.matchAll(/<h2[^>]*>(.*?)<\/h2>/gi);
for (const m of h2Match) {
const clean = m[1].replace(/<[^>]+>/g, '').trim();
if (clean && !h2s.includes(clean)) h2s.push(clean);
}
// Extract Learn This Page triggers
const hasHelpTrigger = content.includes('Learn This Page');
if (h2s.length > 0 || hasHelpTrigger) {
console.log('Page Route File:', rel);
if (h2s.length > 0) console.log(' Headers (H2):', h2s.join(' | '));
console.log(' Has Learn This Page Button:', hasHelpTrigger);
console.log('---');
}
});
`;
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node -e ${JSON.stringify(remoteScript)}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
+62
View File
@@ -0,0 +1,62 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteExtractScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/chunks';
console.log('=== EXTRACTING ALL PAGE HEADERS FROM CHUNKS ===\\n');
const files = fs.readdirSync(root);
files.forEach(f => {
if (!f.endsWith('.js')) return;
const content = fs.readFileSync(path.join(root, f), 'utf8');
// Match header titles in React JSX: e.g. text-3xl font-bold ... >TitleText<
const titleMatches = content.matchAll(/text-3xl[^>]*>([^<]{3,40})</gi);
for (const m of titleMatches) {
console.log(\`Chunk \${f}: "\${m[1].trim()}"\`);
}
// Match tab names in React JSX
const tabMatches = content.matchAll(/role="tab"[^>]*>([^<]{3,30})</gi);
for (const m of tabMatches) {
console.log(\`Chunk \${f} Tab: "\${m[1].trim()}"\`);
}
});
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/extract_client_titles.js';
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
+69
View File
@@ -0,0 +1,69 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteExtractScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server';
console.log('=== EXTRACTING ALL PAGE HEADERS FROM STANDALONE BUILD ===\\n');
function scan(dir) {
if (!fs.existsSync(dir)) return;
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const full = path.join(dir, item.name);
if (item.isDirectory()) {
scan(full);
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
const content = fs.readFileSync(full, 'utf8');
// Look for H2/H1 page header titles or page metadata
const matches = content.matchAll(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/gi);
for (const m of matches) {
const clean = m[1].replace(/<[^>]+>/g, '').trim();
if (clean && clean.length > 2 && clean.length < 60 && !clean.includes('{') && !clean.includes('function')) {
console.log(\`File: \${path.relative(root, full)}\`);
console.log(\` Header: "\${clean}"\`);
}
}
}
}
}
scan(path.join(root, 'app/(dashboard)'));
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/extract_standalone.js';
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
+44
View File
@@ -0,0 +1,44 @@
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
// Execute a shell script on remote server
conn.exec(`python3 -c "
import os, re
root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)'
for dirpath, dirnames, filenames in os.walk(root):
for f in filenames:
if f.endswith('.html') or f.endswith('.js'):
full = os.path.join(dirpath, f)
rel = os.path.relpath(full, root)
try:
content = open(full, 'r', encoding='utf-8', errors='ignore').read()
h2s = re.findall(r'<h[12][^>]*>(.*?)</h[12]>', content)
clean_h2s = [re.sub(r'<[^>]+>', '', h).strip() for h in h2s if h.strip()]
has_learn = 'Learn This Page' in content
if clean_h2s or has_learn:
print(f'Route File: {rel}')
print(f' Headers: {\" | \".join(clean_h2s)}')
print(f' Learn This Page Button: {has_learn}')
print('-' * 40)
except Exception as e:
pass
"`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
+80
View File
@@ -0,0 +1,80 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteScanScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next';
const targetTitles = [
'Overview Dashboard',
'Summary Overview',
'DPI MetaData',
'BackOne Metadata',
'Network Topology',
'Network Infrastructure',
'Traffic Categories',
'Threat Intelligence',
'Detected Threats',
'App Lookup',
'Application Database',
'Encryption Audit',
'Security & Encryption Audit'
];
console.log('=== MATCHING TARGET TITLES IN REMOTE NEXT BUILD ===\\n');
function scan(dir) {
if (!fs.existsSync(dir)) return;
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const full = path.join(dir, item.name);
if (item.isDirectory()) {
scan(full);
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
const content = fs.readFileSync(full, 'utf8');
targetTitles.forEach(t => {
if (content.includes(t)) {
console.log(\`Found "\${t}" in file: \${path.relative(root, full)}\`);
}
});
}
}
}
scan(root);
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/scan_strings.js';
await sftp.put(Buffer.from(remoteScanScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
+94
View File
@@ -0,0 +1,94 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteAuditScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html';
console.log('====================================================');
console.log(' FULL COMPONENT & PAGE AUDIT OF DEMOPLACE.MY.ID ');
console.log('====================================================');
// 1. Audit Client/Server Chunks for Page Headers & HelpTriggers
const chunksDir = path.join(root, '.next/standalone/.next/server/chunks');
if (fs.existsSync(chunksDir)) {
const files = fs.readdirSync(chunksDir);
files.forEach(f => {
if (!f.endsWith('.js')) return;
const content = fs.readFileSync(path.join(chunksDir, f), 'utf8');
// Look for page headers or title definitions
const headerMatch = content.match(/["']([A-Z][A-Za-z0-9\\s]{3,35})["'],\\s*description:/);
if (headerMatch) {
console.log(\`[Chunk \${f}] Found Header Definition: "\${headerMatch[1]}"\`);
}
if (content.includes('Learn This Page')) {
console.log(\`[Chunk \${f}] Contains "Learn This Page" button\`);
}
});
}
// 2. Audit Page Source files in src/app/(dashboard)
const appSrcDir = path.join(root, 'src/app/(dashboard)');
if (fs.existsSync(appSrcDir)) {
function scan(dir) {
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const full = path.join(dir, item.name);
if (item.isDirectory()) {
scan(full);
} else if (item.name === 'page.tsx' || item.name.endsWith('.tsx')) {
const content = fs.readFileSync(full, 'utf8');
const rel = path.relative(appSrcDir, full);
// Find H2 or H1
const h2 = content.match(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/i);
const titleText = h2 ? h2[1].replace(/<[^>]+>/g, '').trim().split('\\n')[0] : 'None';
const hasHelp = content.includes('HelpTrigger') || content.includes('Learn This Page');
console.log(\`Page File: \${rel}\`);
console.log(\` Header Title : \${titleText}\`);
console.log(\` Has HelpButton: \${hasHelp}\`);
console.log('----------------------------------------------------');
}
}
}
scan(appSrcDir);
}
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/audit_remote.js';
await sftp.put(Buffer.from(remoteAuditScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
+8 -2
View File
@@ -14,6 +14,7 @@ import { usePollingKey } from "@/lib/usePolling";
import { AgentModals } from "@/components/admin/AgentModals"; import { AgentModals } from "@/components/admin/AgentModals";
import ExternalAccountModal from "@/components/admin/ExternalAccountModal"; import ExternalAccountModal from "@/components/admin/ExternalAccountModal";
import { getAgentColumns, getExternalAccountColumns } from "./columns"; import { getAgentColumns, getExternalAccountColumns } from "./columns";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function AgentsPage() { export default function AgentsPage() {
const router = useRouter(); const router = useRouter();
@@ -175,11 +176,14 @@ export default function AgentsPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3"> <div>
<Server className="w-6 h-6 text-primary" /> <h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
Agents Inventory Agents Inventory
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />} {isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
</h2> </h2>
<p className="text-muted-foreground mt-1">Managed DPI probes, remote collectors, and probe infrastructure.</p>
</div>
<div className="flex items-center gap-3">
{(role === 'SUPER_ADMIN' || role === 'TENANT_ADMIN') && ( {(role === 'SUPER_ADMIN' || role === 'TENANT_ADMIN') && (
<button <button
onClick={() => setIsCreateOpen(true)} onClick={() => setIsCreateOpen(true)}
@@ -189,6 +193,8 @@ export default function AgentsPage() {
Provision Agent Provision Agent
</button> </button>
)} )}
<HelpTrigger pageId="agents" />
</div>
</div> </div>
{error && ( {error && (
+3 -1
View File
@@ -11,6 +11,7 @@ import { Loader2, ChevronRight, Globe } from "lucide-react";
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters"; import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
import { fmtBytes, getAppFavicon, formatAppLabel } from "@/lib/utils"; import { fmtBytes, getAppFavicon, formatAppLabel } from "@/lib/utils";
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, ResponsiveContainer } from "recharts"; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, ResponsiveContainer } from "recharts";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function AppsPage() { export default function AppsPage() {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -130,7 +131,7 @@ export default function AppsPage() {
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3"> <h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
Applications Applications
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />} {isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
</h2> </h2>
@@ -138,6 +139,7 @@ export default function AppsPage() {
Click any application to see which agents and devices are using it. Click any application to see which agents and devices are using it.
</p> </p>
</div> </div>
<HelpTrigger pageId="apps" />
</div> </div>
<UniversalFilters <UniversalFilters
+2
View File
@@ -11,6 +11,7 @@ import { fmtBytes } from "@/lib/utils";
import { Loader2, ChevronRight, ChevronDown } from "lucide-react"; import { Loader2, ChevronRight, ChevronDown } from "lucide-react";
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters"; import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function DevicesPage() { export default function DevicesPage() {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -171,6 +172,7 @@ export default function DevicesPage() {
<span className="text-slate-500 text-xs">Click an IP to see app usage &amp; flows.</span> <span className="text-slate-500 text-xs">Click an IP to see app usage &amp; flows.</span>
</p> </p>
</div> </div>
<HelpTrigger pageId="devices" />
</div> </div>
<UniversalFilters <UniversalFilters
+7 -2
View File
@@ -7,6 +7,7 @@ import { DataTable, Column } from "@/components/ui/DataTable";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card";
import { Loader2 } from "lucide-react"; import { Loader2 } from "lucide-react";
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters"; import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function DNSPage() { export default function DNSPage() {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -95,11 +96,15 @@ export default function DNSPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3"> <div>
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
DNS Intelligence DNS Intelligence
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />} {isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
</h2> </h2>
<p className="text-muted-foreground mt-1">Domain Name System resolution analytics and query logs.</p>
</div>
<HelpTrigger pageId="dns" />
</div> </div>
<UniversalFilters <UniversalFilters
+6 -1
View File
@@ -24,6 +24,8 @@ function ClickHint() {
); );
} }
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function DpiAnalyticsPage() { export default function DpiAnalyticsPage() {
const { timeRange } = useTimeFilter(); const { timeRange } = useTimeFilter();
// Detail panel state // Detail panel state
@@ -59,13 +61,16 @@ export default function DpiAnalyticsPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between">
<div> <div>
<h1 className="text-3xl font-bold text-white tracking-tight">BackOne Metadata</h1> <h1 className="text-3xl font-bold text-white tracking-tight">DPI MetaData</h1>
<p className="text-slate-400 mt-2"> <p className="text-slate-400 mt-2">
Deep Packet Inspection metadata and fingerprinting.{" "} Deep Packet Inspection metadata and fingerprinting.{" "}
<span className="text-blue-400 text-sm">Click any row to view device-level detail.</span> <span className="text-blue-400 text-sm">Click any row to view device-level detail.</span>
</p> </p>
</div> </div>
<HelpTrigger pageId="dpi-analytics" />
</div>
<Tabs> <Tabs>
{/* ── Hostnames & Servers ──────────────────────────────────────────── */} {/* ── Hostnames & Servers ──────────────────────────────────────────── */}
+6 -1
View File
@@ -11,6 +11,7 @@ import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/compo
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import { Suspense } from "react"; import { Suspense } from "react";
import { HelpTrigger } from "@/components/help/HelpTrigger";
@@ -158,10 +159,14 @@ function EventsContent() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3"> <div>
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
Network Events Network Events
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />} {isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
</h2> </h2>
<p className="text-muted-foreground mt-1">Real-time system, security, and interface network log events.</p>
</div>
<HelpTrigger pageId="events" />
</div> </div>
<UniversalFilters <UniversalFilters
+6 -1
View File
@@ -10,6 +10,7 @@ import { fmtBytes, formatAppLabel } from "@/lib/utils";
import { IpDetails } from "@/components/ui/IpDetails"; import { IpDetails } from "@/components/ui/IpDetails";
import { DeviceDetailModal } from "@/components/ui/DeviceDetailModal"; import { DeviceDetailModal } from "@/components/ui/DeviceDetailModal";
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters"; import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
import { HelpTrigger } from "@/components/help/HelpTrigger";
function explainAppOrPort(appLabel: string | null, domain: string | null, port: number) { function explainAppOrPort(appLabel: string | null, domain: string | null, port: number) {
const label = appLabel || domain || ""; const label = appLabel || domain || "";
@@ -208,10 +209,14 @@ export default function FlowsPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3"> <div>
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
Active Flows Active Flows
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />} {isLoading && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
</h2> </h2>
<p className="text-muted-foreground mt-1">Real-time IP connection flows and protocol analysis.</p>
</div>
<HelpTrigger pageId="flows" />
</div> </div>
<UniversalFilters <UniversalFilters
+5 -3
View File
@@ -8,6 +8,7 @@ import { Loader2 } from "lucide-react";
import { fmtBytes } from "@/lib/utils"; import { fmtBytes } from "@/lib/utils";
import { WorldMap } from "@/components/ui/WorldMap"; import { WorldMap } from "@/components/ui/WorldMap";
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters"; import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function GeographyPage() { export default function GeographyPage() {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -102,14 +103,15 @@ export default function GeographyPage() {
return ( return (
<div className="space-y-8 animate-fade-in pb-10"> <div className="space-y-8 animate-fade-in pb-10">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3"> <h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
Geographic Traffic Geo Traffic
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />} {isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />}
</h2> </h2>
<p className="text-muted-foreground mt-1">Visualize data flow and activity across the globe.</p> <p className="text-muted-foreground mt-1">Geographic distribution of inbound and outbound traffic by country.</p>
</div> </div>
<HelpTrigger pageId="geography" />
</div> </div>
<UniversalFilters <UniversalFilters
+8 -3
View File
@@ -14,6 +14,7 @@ import { Loader2, Bitcoin, Shield, Server, Lock, AlertTriangle, Key, Globe, Netw
import { DeviceDetailModal } from "@/components/ui/DeviceDetailModal"; import { DeviceDetailModal } from "@/components/ui/DeviceDetailModal";
import { TimestampCell } from "@/components/ui/TimestampCell"; import { TimestampCell } from "@/components/ui/TimestampCell";
import { fmtBytes } from "@/lib/utils"; import { fmtBytes } from "@/lib/utils";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function IntelligencePage() { export default function IntelligencePage() {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -370,11 +371,15 @@ export default function IntelligencePage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold tracking-tight text-white flex items-center gap-3"> <div>
Threat Intelligence Feeds <h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
Threat Intelligence
{loadingStats && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />} {loadingStats && <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />}
</h2> </h2>
<p className="text-muted-foreground mt-1">Deep threat intelligence feeds and security detections.</p>
</div>
<HelpTrigger pageId="intelligence" />
</div> </div>
+6 -1
View File
@@ -6,6 +6,8 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card";
import { DropdownFilterSelect } from "@/components/ui/DropdownFilterSelect"; import { DropdownFilterSelect } from "@/components/ui/DropdownFilterSelect";
import { Loader2, Search, AppWindow, HelpCircle, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, X, Info, Tag, Box, Shield, Server } from "lucide-react"; import { Loader2, Search, AppWindow, HelpCircle, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, X, Info, Tag, Box, Shield, Server } from "lucide-react";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function LookupPage() { export default function LookupPage() {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
@@ -54,15 +56,18 @@ export default function LookupPage() {
return ( return (
<div className="space-y-6 animate-fade-in pb-10"> <div className="space-y-6 animate-fade-in pb-10">
<div className="flex items-center justify-between">
<div> <div>
<h1 className="text-3xl font-bold text-white tracking-tight flex items-center gap-3"> <h1 className="text-3xl font-bold text-white tracking-tight flex items-center gap-3">
Application Database App Lookup
{isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />} {isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />}
</h1> </h1>
<p className="text-slate-400 mt-2"> <p className="text-slate-400 mt-2">
Search BackOne's extensive classification database of over 2,500+ apps, protocols, and services. Search BackOne's extensive classification database of over 2,500+ apps, protocols, and services.
</p> </p>
</div> </div>
<HelpTrigger pageId="lookup" />
</div>
{/* Search & Filter Bar */} {/* Search & Filter Bar */}
<div className="flex flex-col sm:flex-row gap-4 animate-slide-up relative z-50" style={{ animationDelay: '50ms' }}> <div className="flex flex-col sm:flex-row gap-4 animate-slide-up relative z-50" style={{ animationDelay: '50ms' }}>
@@ -12,6 +12,8 @@ import {
import { IpDetails } from "@/components/ui/IpDetails"; import { IpDetails } from "@/components/ui/IpDetails";
import { RemoteIpDetailModal } from "@/components/ui/RemoteIpDetailModal"; import { RemoteIpDetailModal } from "@/components/ui/RemoteIpDetailModal";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function NetworkInfrastructurePage() { export default function NetworkInfrastructurePage() {
const [selectedRemoteIp, setSelectedRemoteIp] = useState<string | null>(null); const [selectedRemoteIp, setSelectedRemoteIp] = useState<string | null>(null);
@@ -42,10 +44,13 @@ export default function NetworkInfrastructurePage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between">
<div> <div>
<h1 className="text-3xl font-bold text-white tracking-tight">Network Infrastructure</h1> <h1 className="text-3xl font-bold text-white tracking-tight">Network Topology</h1>
<p className="text-slate-400 mt-2">Physical, logical, and geographic network topologies.</p> <p className="text-slate-400 mt-2">Physical, logical, and geographic network topologies.</p>
</div> </div>
<HelpTrigger pageId="network-infrastructure" />
</div>
<Tabs> <Tabs>
<Tab label="Routing & Geography"> <Tab label="Routing & Geography">
@@ -13,6 +13,7 @@ import { useAppCategories, useContinents } from "@/lib/api-with-context";
import { fmtBytes } from "@/lib/utils"; import { fmtBytes } from "@/lib/utils";
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters"; import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
import { CategoryDetailPanel } from "@/components/network/CategoryDetailPanel"; import { CategoryDetailPanel } from "@/components/network/CategoryDetailPanel";
import { HelpTrigger } from "@/components/help/HelpTrigger";
const COLORS = ['#58a6ff', '#3fb950', '#f0883e', '#bc8cff', '#f85149']; const COLORS = ['#58a6ff', '#3fb950', '#f0883e', '#bc8cff', '#f85149'];
@@ -90,6 +91,7 @@ export default function NetworkIntelligencePage() {
</h2> </h2>
<p className="text-muted-foreground mt-1">Deep packet inspection analytics and geography.</p> <p className="text-muted-foreground mt-1">Deep packet inspection analytics and geography.</p>
</div> </div>
<HelpTrigger pageId="network-intelligence" />
</div> </div>
<UniversalFilters <UniversalFilters
+5 -1
View File
@@ -11,6 +11,7 @@ import TlsVersionsChart from "@/components/security-audit/TlsVersionsChart";
import TlsTables from "@/components/security-audit/TlsTables"; import TlsTables from "@/components/security-audit/TlsTables";
import SslSanTable from "@/components/security-audit/SslSanTable"; import SslSanTable from "@/components/security-audit/SslSanTable";
import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters"; import { UniversalFilters, useUniversalFilterState, FilterConfig } from "@/components/ui/UniversalFilters";
import { HelpTrigger } from "@/components/help/HelpTrigger";
export default function SecurityAuditPage() { export default function SecurityAuditPage() {
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -53,12 +54,15 @@ export default function SecurityAuditPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between">
<div> <div>
<h2 className="text-2xl font-bold text-white tracking-tight">Security & Encryption Audit</h2> <h2 className="text-3xl font-bold text-white tracking-tight">Encryption Audit</h2>
<p className="text-sm text-slate-400 mt-1"> <p className="text-sm text-slate-400 mt-1">
Monitor TLS versions distribution, cipher suites, active certificate properties, and device risk profiles. Monitor TLS versions distribution, cipher suites, active certificate properties, and device risk profiles.
</p> </p>
</div> </div>
<HelpTrigger pageId="security-audit" />
</div>
<UniversalFilters <UniversalFilters
filters={filterConfigs} filters={filterConfigs}
+5 -1
View File
@@ -13,6 +13,7 @@ import { ThreatFilters } from "@/components/threats/ThreatFilters";
import { ThreatRecommendationsDrawer } from "@/components/threats/ThreatRecommendationsDrawer"; import { ThreatRecommendationsDrawer } from "@/components/threats/ThreatRecommendationsDrawer";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import { formatAppLabel } from "@/lib/utils"; import { formatAppLabel } from "@/lib/utils";
import { HelpTrigger } from "@/components/help/HelpTrigger";
// ─── ThreatsContent ─────────────────────────────────────────────────────────── // ─── ThreatsContent ───────────────────────────────────────────────────────────
function ThreatsContent() { function ThreatsContent() {
@@ -215,15 +216,18 @@ function ThreatsContent() {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3"> <h2 className="text-3xl font-bold tracking-tight text-white flex items-center gap-3">
Threat Intelligence Detected Threats
{threats.isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />} {threats.isLoading && <Loader2 className="w-5 h-5 animate-spin text-primary" />}
</h2> </h2>
<p className="text-muted-foreground mt-1">Monitor and respond to network security threats.</p> <p className="text-muted-foreground mt-1">Monitor and respond to network security threats.</p>
</div> </div>
<div className="flex items-center gap-3">
<div className="flex items-center gap-2 text-sm font-medium text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 px-4 py-2 rounded-lg shadow-[0_0_15px_rgba(16,185,129,0.1)]"> <div className="flex items-center gap-2 text-sm font-medium text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 px-4 py-2 rounded-lg shadow-[0_0_15px_rgba(16,185,129,0.1)]">
<ShieldCheck className="h-4 w-4" /> <ShieldCheck className="h-4 w-4" />
<span>Active Monitoring</span> <span>Active Monitoring</span>
</div> </div>
<HelpTrigger pageId="threats" />
</div>
</div> </div>
{/* Filters above the table */} {/* Filters above the table */}